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"
7 
8 #include <limits>
9 #include <map>
10 #include <sstream>
11 #include <type_traits>
12 
13 #include "flutter/fml/build_config.h"
14 #include "flutter/testing/testing.h"
18 #include "impeller/geometry/half.h"
20 #include "impeller/geometry/rect.h"
23 #include "impeller/geometry/size.h"
24 
25 // TODO(zanderso): https://github.com/flutter/flutter/issues/127701
26 // NOLINTBEGIN(bugprone-unchecked-optional-access)
27 
28 namespace impeller {
29 namespace testing {
30 
31 TEST(GeometryTest, ScalarNearlyEqual) {
32  ASSERT_FALSE(ScalarNearlyEqual(0.0021f, 0.001f));
33  ASSERT_TRUE(ScalarNearlyEqual(0.0019f, 0.001f));
34  ASSERT_TRUE(ScalarNearlyEqual(0.002f, 0.001f, 0.0011f));
35  ASSERT_FALSE(ScalarNearlyEqual(0.002f, 0.001f, 0.0009f));
36  ASSERT_TRUE(ScalarNearlyEqual(
37  1.0f, 1.0f + std::numeric_limits<float>::epsilon() * 4));
38 }
39 
40 TEST(GeometryTest, MakeColumn) {
41  auto matrix = Matrix::MakeColumn(1, 2, 3, 4, //
42  5, 6, 7, 8, //
43  9, 10, 11, 12, //
44  13, 14, 15, 16);
45 
46  auto expect = Matrix{1, 2, 3, 4, //
47  5, 6, 7, 8, //
48  9, 10, 11, 12, //
49  13, 14, 15, 16};
50 
51  ASSERT_TRUE(matrix == expect);
52 }
53 
54 TEST(GeometryTest, MakeRow) {
55  auto matrix = Matrix::MakeRow(1, 2, 3, 4, //
56  5, 6, 7, 8, //
57  9, 10, 11, 12, //
58  13, 14, 15, 16);
59 
60  auto expect = Matrix{1, 5, 9, 13, //
61  2, 6, 10, 14, //
62  3, 7, 11, 15, //
63  4, 8, 12, 16};
64 
65  ASSERT_TRUE(matrix == expect);
66 }
67 
68 TEST(GeometryTest, RotationMatrix) {
69  auto rotation = Matrix::MakeRotationZ(Radians{kPiOver4});
70  // clang-format off
71  auto expect = Matrix{k1OverSqrt2, k1OverSqrt2, 0, 0,
72  -k1OverSqrt2, k1OverSqrt2, 0, 0,
73  0, 0, 1, 0,
74  0, 0, 0, 1};
75  // clang-format on
76  ASSERT_MATRIX_NEAR(rotation, expect);
77 }
78 
79 TEST(GeometryTest, InvertMultMatrix) {
80  {
81  auto rotation = Matrix::MakeRotationZ(Radians{kPiOver4});
82  auto invert = rotation.Invert();
83  // clang-format off
84  auto expect = Matrix{k1OverSqrt2, -k1OverSqrt2, 0, 0,
85  k1OverSqrt2, k1OverSqrt2, 0, 0,
86  0, 0, 1, 0,
87  0, 0, 0, 1};
88  // clang-format on
89  ASSERT_MATRIX_NEAR(invert, expect);
90  }
91  {
92  auto scale = Matrix::MakeScale(Vector2{2, 4});
93  auto invert = scale.Invert();
94  auto expect = Matrix{0.5, 0, 0, 0, //
95  0, 0.25, 0, 0, //
96  0, 0, 1, 0, //
97  0, 0, 0, 1};
98  ASSERT_MATRIX_NEAR(invert, expect);
99  }
100 }
101 
102 TEST(GeometryTest, MatrixBasis) {
103  auto matrix = Matrix{1, 2, 3, 4, //
104  5, 6, 7, 8, //
105  9, 10, 11, 12, //
106  13, 14, 15, 16};
107  auto basis = matrix.Basis();
108  auto expect = Matrix{1, 2, 3, 0, //
109  5, 6, 7, 0, //
110  9, 10, 11, 0, //
111  0, 0, 0, 1};
112  ASSERT_MATRIX_NEAR(basis, expect);
113 }
114 
115 TEST(GeometryTest, MutliplicationMatrix) {
116  auto rotation = Matrix::MakeRotationZ(Radians{kPiOver4});
117  auto invert = rotation.Invert();
118  ASSERT_MATRIX_NEAR(rotation * invert, Matrix{});
119 }
120 
121 TEST(GeometryTest, DeterminantTest) {
122  auto matrix = Matrix{3, 4, 14, 155, 2, 1, 3, 4, 2, 3, 2, 1, 1, 2, 4, 2};
123  ASSERT_EQ(matrix.GetDeterminant(), -1889);
124 }
125 
126 TEST(GeometryTest, InvertMatrix) {
127  auto inverted = Matrix{10, -9, -12, 8, //
128  7, -12, 11, 22, //
129  -10, 10, 3, 6, //
130  -2, 22, 2, 1}
131  .Invert();
132 
133  auto result = Matrix{
134  438.0 / 85123.0, 1751.0 / 85123.0, -7783.0 / 85123.0, 4672.0 / 85123.0,
135  393.0 / 85123.0, -178.0 / 85123.0, -570.0 / 85123.0, 4192 / 85123.0,
136  -5230.0 / 85123.0, 2802.0 / 85123.0, -3461.0 / 85123.0, 962.0 / 85123.0,
137  2690.0 / 85123.0, 1814.0 / 85123.0, 3896.0 / 85123.0, 319.0 / 85123.0};
138 
139  ASSERT_MATRIX_NEAR(inverted, result);
140 }
141 
142 TEST(GeometryTest, TestDecomposition) {
143  auto rotated = Matrix::MakeRotationZ(Radians{kPiOver4});
144 
145  auto result = rotated.Decompose();
146 
147  ASSERT_TRUE(result.has_value());
148 
149  MatrixDecomposition res = result.value();
150 
151  auto quaternion = Quaternion{{0.0, 0.0, 1.0}, kPiOver4};
152  ASSERT_QUATERNION_NEAR(res.rotation, quaternion);
153 }
154 
155 TEST(GeometryTest, TestDecomposition2) {
156  auto rotated = Matrix::MakeRotationZ(Radians{kPiOver4});
157  auto scaled = Matrix::MakeScale({2.0, 3.0, 1.0});
158  auto translated = Matrix::MakeTranslation({-200, 750, 20});
159 
160  auto result = (translated * rotated * scaled).Decompose();
161 
162  ASSERT_TRUE(result.has_value());
163 
164  MatrixDecomposition res = result.value();
165 
166  auto quaternion = Quaternion{{0.0, 0.0, 1.0}, kPiOver4};
167 
168  ASSERT_QUATERNION_NEAR(res.rotation, quaternion);
169 
170  ASSERT_FLOAT_EQ(res.translation.x, -200);
171  ASSERT_FLOAT_EQ(res.translation.y, 750);
172  ASSERT_FLOAT_EQ(res.translation.z, 20);
173 
174  ASSERT_FLOAT_EQ(res.scale.x, 2);
175  ASSERT_FLOAT_EQ(res.scale.y, 3);
176  ASSERT_FLOAT_EQ(res.scale.z, 1);
177 }
178 
179 TEST(GeometryTest, TestRecomposition) {
180  /*
181  * Decomposition.
182  */
183  auto rotated = Matrix::MakeRotationZ(Radians{kPiOver4});
184 
185  auto result = rotated.Decompose();
186 
187  ASSERT_TRUE(result.has_value());
188 
189  MatrixDecomposition res = result.value();
190 
191  auto quaternion = Quaternion{{0.0, 0.0, 1.0}, kPiOver4};
192 
193  ASSERT_QUATERNION_NEAR(res.rotation, quaternion);
194 
195  /*
196  * Recomposition.
197  */
198  ASSERT_MATRIX_NEAR(rotated, Matrix{res});
199 }
200 
201 TEST(GeometryTest, TestRecomposition2) {
202  auto matrix = Matrix::MakeTranslation({100, 100, 100}) *
204  Matrix::MakeScale({2.0, 2.0, 2.0});
205 
206  auto result = matrix.Decompose();
207 
208  ASSERT_TRUE(result.has_value());
209 
210  ASSERT_MATRIX_NEAR(matrix, Matrix{result.value()});
211 }
212 
213 TEST(GeometryTest, MatrixVectorMultiplication) {
214  {
215  auto matrix = Matrix::MakeTranslation({100, 100, 100}) *
217  Matrix::MakeScale({2.0, 2.0, 2.0});
218  auto vector = Vector4(10, 20, 30, 2);
219 
220  Vector4 result = matrix * vector;
221  auto expected = Vector4(160, 220, 260, 2);
222  ASSERT_VECTOR4_NEAR(result, expected);
223  }
224 
225  {
226  auto matrix = Matrix::MakeTranslation({100, 100, 100}) *
228  Matrix::MakeScale({2.0, 2.0, 2.0});
229  auto vector = Vector3(10, 20, 30);
230 
231  Vector3 result = matrix * vector;
232  auto expected = Vector3(60, 120, 160);
233  ASSERT_VECTOR3_NEAR(result, expected);
234  }
235 
236  {
237  auto matrix = Matrix::MakeTranslation({100, 100, 100}) *
239  Matrix::MakeScale({2.0, 2.0, 2.0});
240  auto vector = Point(10, 20);
241 
242  Point result = matrix * vector;
243  auto expected = Point(60, 120);
244  ASSERT_POINT_NEAR(result, expected);
245  }
246 
247  // Matrix Vector ops should respect perspective transforms.
248  {
249  auto matrix = Matrix::MakePerspective(Radians(kPiOver2), 1, 1, 100);
250  auto vector = Vector3(3, 3, -3);
251 
252  Vector3 result = matrix * vector;
253  auto expected = Vector3(-1, -1, 1.3468);
254  ASSERT_VECTOR3_NEAR(result, expected);
255  }
256 
257  {
258  auto matrix = Matrix::MakePerspective(Radians(kPiOver2), 1, 1, 100) *
259  Matrix::MakeTranslation(Vector3(0, 0, -3));
260  auto point = Point(3, 3);
261 
262  Point result = matrix * point;
263  auto expected = Point(-1, -1);
264  ASSERT_POINT_NEAR(result, expected);
265  }
266 
267  // Resolves to 0 on perspective singularity.
268  {
269  auto matrix = Matrix::MakePerspective(Radians(kPiOver2), 1, 1, 100);
270  auto point = Point(3, 3);
271 
272  Point result = matrix * point;
273  auto expected = Point(0, 0);
274  ASSERT_POINT_NEAR(result, expected);
275  }
276 }
277 
278 TEST(GeometryTest, MatrixMakeRotationFromQuaternion) {
279  {
280  auto matrix = Matrix::MakeRotation(Quaternion({1, 0, 0}, kPiOver2));
281  auto expected = Matrix::MakeRotationX(Radians(kPiOver2));
282  ASSERT_MATRIX_NEAR(matrix, expected);
283  }
284 
285  {
286  auto matrix = Matrix::MakeRotation(Quaternion({0, 1, 0}, kPiOver2));
287  auto expected = Matrix::MakeRotationY(Radians(kPiOver2));
288  ASSERT_MATRIX_NEAR(matrix, expected);
289  }
290 
291  {
292  auto matrix = Matrix::MakeRotation(Quaternion({0, 0, 1}, kPiOver2));
293  auto expected = Matrix::MakeRotationZ(Radians(kPiOver2));
294  ASSERT_MATRIX_NEAR(matrix, expected);
295  }
296 }
297 
298 TEST(GeometryTest, MatrixTransformDirection) {
299  {
300  auto matrix = Matrix::MakeTranslation({100, 100, 100}) *
302  Matrix::MakeScale({2.0, 2.0, 2.0});
303  auto vector = Vector4(10, 20, 30, 2);
304 
305  Vector4 result = matrix.TransformDirection(vector);
306  auto expected = Vector4(-40, 20, 60, 2);
307  ASSERT_VECTOR4_NEAR(result, expected);
308  }
309 
310  {
311  auto matrix = Matrix::MakeTranslation({100, 100, 100}) *
313  Matrix::MakeScale({2.0, 2.0, 2.0});
314  auto vector = Vector3(10, 20, 30);
315 
316  Vector3 result = matrix.TransformDirection(vector);
317  auto expected = Vector3(-40, 20, 60);
318  ASSERT_VECTOR3_NEAR(result, expected);
319  }
320 
321  {
322  auto matrix = Matrix::MakeTranslation({0, -0.4, 100}) *
324  Matrix::MakeScale({2.0, 2.0, 2.0});
325  auto vector = Point(10, 20);
326 
327  Point result = matrix.TransformDirection(vector);
328  auto expected = Point(-40, 20);
329  ASSERT_POINT_NEAR(result, expected);
330  }
331 }
332 
333 TEST(GeometryTest, MatrixGetMaxBasisLengthXY) {
334  {
335  auto m = Matrix::MakeScale({3, 1, 1});
336  ASSERT_EQ(m.GetMaxBasisLengthXY(), 3);
337 
338  m = m * Matrix::MakeSkew(0, 4);
339  ASSERT_EQ(m.GetMaxBasisLengthXY(), 5);
340  }
341 
342  {
343  auto m = Matrix::MakeScale({-3, 4, 7});
344  ASSERT_EQ(m.GetMaxBasisLengthXY(), 4);
345  }
346 
347  {
348  // clang-format off
349  auto m = Matrix::MakeColumn(
350  1.0f, 0.0f, 0.0f, 0.0f,
351  0.0f, 1.0f, 0.0f, 0.0f,
352  4.0f, 0.0f, 1.0f, 0.0f,
353  0.0f, 0.0f, 0.0f, 1.0f
354  );
355  // clang-format on
356  ASSERT_EQ(m.GetMaxBasisLengthXY(), 1.0f);
357  }
358 }
359 
360 TEST(GeometryTest, MatrixMakeOrthographic) {
361  {
362  auto m = Matrix::MakeOrthographic(Size(100, 200));
363  auto expect = Matrix{
364  0.02, 0, 0, 0, //
365  0, -0.01, 0, 0, //
366  0, 0, 0, 0, //
367  -1, 1, 0.5, 1, //
368  };
369  ASSERT_MATRIX_NEAR(m, expect);
370  }
371 
372  {
373  auto m = Matrix::MakeOrthographic(Size(400, 100));
374  auto expect = Matrix{
375  0.005, 0, 0, 0, //
376  0, -0.02, 0, 0, //
377  0, 0, 0, 0, //
378  -1, 1, 0.5, 1, //
379  };
380  ASSERT_MATRIX_NEAR(m, expect);
381  }
382 }
383 
384 TEST(GeometryTest, MatrixMakePerspective) {
385  {
386  auto m = Matrix::MakePerspective(Degrees(60), Size(100, 200), 1, 10);
387  auto expect = Matrix{
388  3.4641, 0, 0, 0, //
389  0, 1.73205, 0, 0, //
390  0, 0, 1.11111, 1, //
391  0, 0, -1.11111, 0, //
392  };
393  ASSERT_MATRIX_NEAR(m, expect);
394  }
395 
396  {
397  auto m = Matrix::MakePerspective(Radians(1), 2, 10, 20);
398  auto expect = Matrix{
399  0.915244, 0, 0, 0, //
400  0, 1.83049, 0, 0, //
401  0, 0, 2, 1, //
402  0, 0, -20, 0, //
403  };
404  ASSERT_MATRIX_NEAR(m, expect);
405  }
406 }
407 
408 TEST(GeometryTest, MatrixGetBasisVectors) {
409  {
410  auto m = Matrix();
411  Vector3 x = m.GetBasisX();
412  Vector3 y = m.GetBasisY();
413  Vector3 z = m.GetBasisZ();
414  ASSERT_VECTOR3_NEAR(x, Vector3(1, 0, 0));
415  ASSERT_VECTOR3_NEAR(y, Vector3(0, 1, 0));
416  ASSERT_VECTOR3_NEAR(z, Vector3(0, 0, 1));
417  }
418 
419  {
422  Matrix::MakeScale(Vector3(2, 3, 4));
423  Vector3 x = m.GetBasisX();
424  Vector3 y = m.GetBasisY();
425  Vector3 z = m.GetBasisZ();
426  ASSERT_VECTOR3_NEAR(x, Vector3(0, 2, 0));
427  ASSERT_VECTOR3_NEAR(y, Vector3(0, 0, 3));
428  ASSERT_VECTOR3_NEAR(z, Vector3(4, 0, 0));
429  }
430 }
431 
432 TEST(GeometryTest, MatrixGetDirectionScale) {
433  {
434  auto m = Matrix();
435  Scalar result = m.GetDirectionScale(Vector3{1, 0, 0});
436  ASSERT_FLOAT_EQ(result, 1);
437  }
438 
439  {
440  auto m = Matrix::MakeRotationX(Degrees{10}) *
443  Scalar result = m.GetDirectionScale(Vector3{0, 1, 0});
444  ASSERT_FLOAT_EQ(result, 1);
445  }
446 
447  {
449  Matrix::MakeScale(Vector3(3, 4, 5));
450  Scalar result = m.GetDirectionScale(Vector3{2, 0, 0});
451  ASSERT_FLOAT_EQ(result, 8);
452  }
453 }
454 
455 TEST(GeometryTest, MatrixTranslationScaleOnly) {
456  {
457  auto m = Matrix();
458  bool result = m.IsTranslationScaleOnly();
459  ASSERT_TRUE(result);
460  }
461 
462  {
463  auto m = Matrix::MakeScale(Vector3(2, 3, 4));
464  bool result = m.IsTranslationScaleOnly();
465  ASSERT_TRUE(result);
466  }
467 
468  {
469  auto m = Matrix::MakeTranslation(Vector3(2, 3, 4));
470  bool result = m.IsTranslationScaleOnly();
471  ASSERT_TRUE(result);
472  }
473 
474  {
475  auto m = Matrix::MakeRotationZ(Degrees(10));
476  bool result = m.IsTranslationScaleOnly();
477  ASSERT_FALSE(result);
478  }
479 }
480 
481 TEST(GeometryTest, MatrixLookAt) {
482  {
483  auto m = Matrix::MakeLookAt(Vector3(0, 0, -1), Vector3(0, 0, 1),
484  Vector3(0, 1, 0));
485  auto expected = Matrix{
486  1, 0, 0, 0, //
487  0, 1, 0, 0, //
488  0, 0, 1, 0, //
489  0, 0, 1, 1, //
490  };
491  ASSERT_MATRIX_NEAR(m, expected);
492  }
493 
494  // Sideways tilt.
495  {
496  auto m = Matrix::MakeLookAt(Vector3(0, 0, -1), Vector3(0, 0, 1),
497  Vector3(1, 1, 0).Normalize());
498 
499  // clang-format off
500  auto expected = Matrix{
501  k1OverSqrt2, k1OverSqrt2, 0, 0,
502  -k1OverSqrt2, k1OverSqrt2, 0, 0,
503  0, 0, 1, 0,
504  0, 0, 1, 1,
505  };
506  // clang-format on
507  ASSERT_MATRIX_NEAR(m, expected);
508  }
509 
510  // Half way between +x and -y, yaw 90
511  {
512  auto m =
513  Matrix::MakeLookAt(Vector3(), Vector3(10, -10, 0), Vector3(0, 0, -1));
514 
515  // clang-format off
516  auto expected = Matrix{
517  -k1OverSqrt2, 0, k1OverSqrt2, 0,
518  -k1OverSqrt2, 0, -k1OverSqrt2, 0,
519  0, -1, 0, 0,
520  0, 0, 0, 1,
521  };
522  // clang-format on
523  ASSERT_MATRIX_NEAR(m, expected);
524  }
525 }
526 
527 TEST(GeometryTest, QuaternionLerp) {
528  auto q1 = Quaternion{{0.0, 0.0, 1.0}, 0.0};
529  auto q2 = Quaternion{{0.0, 0.0, 1.0}, kPiOver4};
530 
531  auto q3 = q1.Slerp(q2, 0.5);
532 
533  auto expected = Quaternion{{0.0, 0.0, 1.0}, kPiOver4 / 2.0};
534 
535  ASSERT_QUATERNION_NEAR(q3, expected);
536 }
537 
538 TEST(GeometryTest, QuaternionVectorMultiply) {
539  {
540  Quaternion q({0, 0, 1}, 0);
541  Vector3 v(0, 1, 0);
542 
543  Vector3 result = q * v;
544  Vector3 expected(0, 1, 0);
545 
546  ASSERT_VECTOR3_NEAR(result, expected);
547  }
548 
549  {
550  Quaternion q({0, 0, 1}, k2Pi);
551  Vector3 v(1, 0, 0);
552 
553  Vector3 result = q * v;
554  Vector3 expected(1, 0, 0);
555 
556  ASSERT_VECTOR3_NEAR(result, expected);
557  }
558 
559  {
560  Quaternion q({0, 0, 1}, kPiOver4);
561  Vector3 v(0, 1, 0);
562 
563  Vector3 result = q * v;
564  Vector3 expected(-k1OverSqrt2, k1OverSqrt2, 0);
565 
566  ASSERT_VECTOR3_NEAR(result, expected);
567  }
568 
569  {
570  Quaternion q(Vector3(1, 0, 1).Normalize(), kPi);
571  Vector3 v(0, 0, -1);
572 
573  Vector3 result = q * v;
574  Vector3 expected(-1, 0, 0);
575 
576  ASSERT_VECTOR3_NEAR(result, expected);
577  }
578 }
579 
580 TEST(GeometryTest, CanGenerateMipCounts) {
581  ASSERT_EQ((Size{128, 128}.MipCount()), 7u);
582  ASSERT_EQ((Size{128, 256}.MipCount()), 8u);
583  ASSERT_EQ((Size{128, 130}.MipCount()), 8u);
584  ASSERT_EQ((Size{128, 257}.MipCount()), 9u);
585  ASSERT_EQ((Size{257, 128}.MipCount()), 9u);
586  ASSERT_EQ((Size{128, 0}.MipCount()), 1u);
587  ASSERT_EQ((Size{128, -25}.MipCount()), 1u);
588  ASSERT_EQ((Size{-128, 25}.MipCount()), 1u);
589  ASSERT_EQ((Size{1, 1}.MipCount()), 1u);
590  ASSERT_EQ((Size{0, 0}.MipCount()), 1u);
591 }
592 
593 TEST(GeometryTest, CanConvertTTypesExplicitly) {
594  {
595  Point p1(1.0, 2.0);
596  IPoint p2 = static_cast<IPoint>(p1);
597  ASSERT_EQ(p2.x, 1u);
598  ASSERT_EQ(p2.y, 2u);
599  }
600 
601  {
602  Size s1(1.0, 2.0);
603  ISize s2 = static_cast<ISize>(s1);
604  ASSERT_EQ(s2.width, 1u);
605  ASSERT_EQ(s2.height, 2u);
606  }
607 
608  {
609  Size s1(1.0, 2.0);
610  Point p1 = static_cast<Point>(s1);
611  ASSERT_EQ(p1.x, 1u);
612  ASSERT_EQ(p1.y, 2u);
613  }
614 }
615 
616 TEST(GeometryTest, CanPerformAlgebraicPointOps) {
617  {
618  IPoint p1(1, 2);
619  IPoint p2 = p1 + IPoint(1, 2);
620  ASSERT_EQ(p2.x, 2u);
621  ASSERT_EQ(p2.y, 4u);
622  }
623 
624  {
625  IPoint p1(3, 6);
626  IPoint p2 = p1 - IPoint(1, 2);
627  ASSERT_EQ(p2.x, 2u);
628  ASSERT_EQ(p2.y, 4u);
629  }
630 
631  {
632  IPoint p1(1, 2);
633  IPoint p2 = p1 * IPoint(2, 3);
634  ASSERT_EQ(p2.x, 2u);
635  ASSERT_EQ(p2.y, 6u);
636  }
637 
638  {
639  IPoint p1(2, 6);
640  IPoint p2 = p1 / IPoint(2, 3);
641  ASSERT_EQ(p2.x, 1u);
642  ASSERT_EQ(p2.y, 2u);
643  }
644 }
645 
646 TEST(GeometryTest, CanPerformAlgebraicPointOpsWithArithmeticTypes) {
647  // LHS
648  {
649  IPoint p1(1, 2);
650  IPoint p2 = p1 * 2.0f;
651  ASSERT_EQ(p2.x, 2u);
652  ASSERT_EQ(p2.y, 4u);
653  }
654 
655  {
656  IPoint p1(2, 6);
657  IPoint p2 = p1 / 2.0f;
658  ASSERT_EQ(p2.x, 1u);
659  ASSERT_EQ(p2.y, 3u);
660  }
661 
662  // RHS
663  {
664  IPoint p1(1, 2);
665  IPoint p2 = 2.0f * p1;
666  ASSERT_EQ(p2.x, 2u);
667  ASSERT_EQ(p2.y, 4u);
668  }
669 
670  {
671  IPoint p1(2, 6);
672  IPoint p2 = 12.0f / p1;
673  ASSERT_EQ(p2.x, 6u);
674  ASSERT_EQ(p2.y, 2u);
675  }
676 }
677 
678 TEST(GeometryTest, PointIntegerCoercesToFloat) {
679  // Integer on LHS, float on RHS
680  {
681  IPoint p1(1, 2);
682  Point p2 = p1 + Point(1, 2);
683  ASSERT_FLOAT_EQ(p2.x, 2u);
684  ASSERT_FLOAT_EQ(p2.y, 4u);
685  }
686 
687  {
688  IPoint p1(3, 6);
689  Point p2 = p1 - Point(1, 2);
690  ASSERT_FLOAT_EQ(p2.x, 2u);
691  ASSERT_FLOAT_EQ(p2.y, 4u);
692  }
693 
694  {
695  IPoint p1(1, 2);
696  Point p2 = p1 * Point(2, 3);
697  ASSERT_FLOAT_EQ(p2.x, 2u);
698  ASSERT_FLOAT_EQ(p2.y, 6u);
699  }
700 
701  {
702  IPoint p1(2, 6);
703  Point p2 = p1 / Point(2, 3);
704  ASSERT_FLOAT_EQ(p2.x, 1u);
705  ASSERT_FLOAT_EQ(p2.y, 2u);
706  }
707 
708  // Float on LHS, integer on RHS
709  {
710  Point p1(1, 2);
711  Point p2 = p1 + IPoint(1, 2);
712  ASSERT_FLOAT_EQ(p2.x, 2u);
713  ASSERT_FLOAT_EQ(p2.y, 4u);
714  }
715 
716  {
717  Point p1(3, 6);
718  Point p2 = p1 - IPoint(1, 2);
719  ASSERT_FLOAT_EQ(p2.x, 2u);
720  ASSERT_FLOAT_EQ(p2.y, 4u);
721  }
722 
723  {
724  Point p1(1, 2);
725  Point p2 = p1 * IPoint(2, 3);
726  ASSERT_FLOAT_EQ(p2.x, 2u);
727  ASSERT_FLOAT_EQ(p2.y, 6u);
728  }
729 
730  {
731  Point p1(2, 6);
732  Point p2 = p1 / IPoint(2, 3);
733  ASSERT_FLOAT_EQ(p2.x, 1u);
734  ASSERT_FLOAT_EQ(p2.y, 2u);
735  }
736 }
737 
738 TEST(GeometryTest, SizeCoercesToPoint) {
739  // Point on LHS, Size on RHS
740  {
741  IPoint p1(1, 2);
742  IPoint p2 = p1 + ISize(1, 2);
743  ASSERT_EQ(p2.x, 2u);
744  ASSERT_EQ(p2.y, 4u);
745  }
746 
747  {
748  IPoint p1(3, 6);
749  IPoint p2 = p1 - ISize(1, 2);
750  ASSERT_EQ(p2.x, 2u);
751  ASSERT_EQ(p2.y, 4u);
752  }
753 
754  {
755  IPoint p1(1, 2);
756  IPoint p2 = p1 * ISize(2, 3);
757  ASSERT_EQ(p2.x, 2u);
758  ASSERT_EQ(p2.y, 6u);
759  }
760 
761  {
762  IPoint p1(2, 6);
763  IPoint p2 = p1 / ISize(2, 3);
764  ASSERT_EQ(p2.x, 1u);
765  ASSERT_EQ(p2.y, 2u);
766  }
767 
768  // Size on LHS, Point on RHS
769  {
770  ISize p1(1, 2);
771  IPoint p2 = p1 + IPoint(1, 2);
772  ASSERT_EQ(p2.x, 2u);
773  ASSERT_EQ(p2.y, 4u);
774  }
775 
776  {
777  ISize p1(3, 6);
778  IPoint p2 = p1 - IPoint(1, 2);
779  ASSERT_EQ(p2.x, 2u);
780  ASSERT_EQ(p2.y, 4u);
781  }
782 
783  {
784  ISize p1(1, 2);
785  IPoint p2 = p1 * IPoint(2, 3);
786  ASSERT_EQ(p2.x, 2u);
787  ASSERT_EQ(p2.y, 6u);
788  }
789 
790  {
791  ISize p1(2, 6);
792  IPoint p2 = p1 / IPoint(2, 3);
793  ASSERT_EQ(p2.x, 1u);
794  ASSERT_EQ(p2.y, 2u);
795  }
796 }
797 
798 TEST(GeometryTest, CanUsePointAssignmentOperators) {
799  // Point on RHS
800  {
801  IPoint p(1, 2);
802  p += IPoint(1, 2);
803  ASSERT_EQ(p.x, 2u);
804  ASSERT_EQ(p.y, 4u);
805  }
806 
807  {
808  IPoint p(3, 6);
809  p -= IPoint(1, 2);
810  ASSERT_EQ(p.x, 2u);
811  ASSERT_EQ(p.y, 4u);
812  }
813 
814  {
815  IPoint p(1, 2);
816  p *= IPoint(2, 3);
817  ASSERT_EQ(p.x, 2u);
818  ASSERT_EQ(p.y, 6u);
819  }
820 
821  {
822  IPoint p(2, 6);
823  p /= IPoint(2, 3);
824  ASSERT_EQ(p.x, 1u);
825  ASSERT_EQ(p.y, 2u);
826  }
827 
828  // Size on RHS
829  {
830  IPoint p(1, 2);
831  p += ISize(1, 2);
832  ASSERT_EQ(p.x, 2u);
833  ASSERT_EQ(p.y, 4u);
834  }
835 
836  {
837  IPoint p(3, 6);
838  p -= ISize(1, 2);
839  ASSERT_EQ(p.x, 2u);
840  ASSERT_EQ(p.y, 4u);
841  }
842 
843  {
844  IPoint p(1, 2);
845  p *= ISize(2, 3);
846  ASSERT_EQ(p.x, 2u);
847  ASSERT_EQ(p.y, 6u);
848  }
849 
850  {
851  IPoint p(2, 6);
852  p /= ISize(2, 3);
853  ASSERT_EQ(p.x, 1u);
854  ASSERT_EQ(p.y, 2u);
855  }
856 
857  // Arithmetic type on RHS
858  {
859  IPoint p(1, 2);
860  p *= 3;
861  ASSERT_EQ(p.x, 3u);
862  ASSERT_EQ(p.y, 6u);
863  }
864 
865  {
866  IPoint p(3, 6);
867  p /= 3;
868  ASSERT_EQ(p.x, 1u);
869  ASSERT_EQ(p.y, 2u);
870  }
871 }
872 
873 TEST(GeometryTest, PointDotProduct) {
874  {
875  Point p(1, 0);
876  Scalar s = p.Dot(Point(-1, 0));
877  ASSERT_FLOAT_EQ(s, -1);
878  }
879 
880  {
881  Point p(0, -1);
882  Scalar s = p.Dot(Point(-1, 0));
883  ASSERT_FLOAT_EQ(s, 0);
884  }
885 
886  {
887  Point p(1, 2);
888  Scalar s = p.Dot(Point(3, -4));
889  ASSERT_FLOAT_EQ(s, -5);
890  }
891 }
892 
893 TEST(GeometryTest, PointCrossProduct) {
894  {
895  Point p(1, 0);
896  Scalar s = p.Cross(Point(-1, 0));
897  ASSERT_FLOAT_EQ(s, 0);
898  }
899 
900  {
901  Point p(0, -1);
902  Scalar s = p.Cross(Point(-1, 0));
903  ASSERT_FLOAT_EQ(s, -1);
904  }
905 
906  {
907  Point p(1, 2);
908  Scalar s = p.Cross(Point(3, -4));
909  ASSERT_FLOAT_EQ(s, -10);
910  }
911 }
912 
913 TEST(GeometryTest, PointReflect) {
914  {
915  Point axis = Point(0, 1);
916  Point a(2, 3);
917  auto reflected = a.Reflect(axis);
918  auto expected = Point(2, -3);
919  ASSERT_POINT_NEAR(reflected, expected);
920  }
921 
922  {
923  Point axis = Point(1, 1).Normalize();
924  Point a(1, 0);
925  auto reflected = a.Reflect(axis);
926  auto expected = Point(0, -1);
927  ASSERT_POINT_NEAR(reflected, expected);
928  }
929 
930  {
931  Point axis = Point(1, 1).Normalize();
932  Point a(-1, -1);
933  auto reflected = a.Reflect(axis);
934  ASSERT_POINT_NEAR(reflected, -a);
935  }
936 }
937 
938 TEST(GeometryTest, PointAbs) {
939  Point a(-1, -2);
940  auto a_abs = a.Abs();
941  auto expected = Point(1, 2);
942  ASSERT_POINT_NEAR(a_abs, expected);
943 }
944 
945 TEST(GeometryTest, PointRotate) {
946  {
947  Point a(1, 0);
948  auto rotated = a.Rotate(Radians{kPiOver2});
949  auto expected = Point(0, 1);
950  ASSERT_POINT_NEAR(rotated, expected);
951  }
952 
953  {
954  Point a(1, 0);
955  auto rotated = a.Rotate(Radians{-kPiOver2});
956  auto expected = Point(0, -1);
957  ASSERT_POINT_NEAR(rotated, expected);
958  }
959 
960  {
961  Point a(1, 0);
962  auto rotated = a.Rotate(Radians{kPi});
963  auto expected = Point(-1, 0);
964  ASSERT_POINT_NEAR(rotated, expected);
965  }
966 
967  {
968  Point a(1, 0);
969  auto rotated = a.Rotate(Radians{kPi * 1.5});
970  auto expected = Point(0, -1);
971  ASSERT_POINT_NEAR(rotated, expected);
972  }
973 }
974 
975 TEST(GeometryTest, PointAngleTo) {
976  // Negative result in the CCW (with up = -Y) direction.
977  {
978  Point a(1, 1);
979  Point b(1, -1);
980  Radians actual = a.AngleTo(b);
981  Radians expected = Radians{-kPi / 2};
982  ASSERT_FLOAT_EQ(actual.radians, expected.radians);
983  }
984 
985  // Check the other direction to ensure the result is signed correctly.
986  {
987  Point a(1, -1);
988  Point b(1, 1);
989  Radians actual = a.AngleTo(b);
990  Radians expected = Radians{kPi / 2};
991  ASSERT_FLOAT_EQ(actual.radians, expected.radians);
992  }
993 
994  // Differences in magnitude should have no impact on the result.
995  {
996  Point a(100, -100);
997  Point b(0.01, 0.01);
998  Radians actual = a.AngleTo(b);
999  Radians expected = Radians{kPi / 2};
1000  ASSERT_FLOAT_EQ(actual.radians, expected.radians);
1001  }
1002 }
1003 
1004 TEST(GeometryTest, PointMin) {
1005  Point p(1, 2);
1006  Point result = p.Min({0, 10});
1007  Point expected(0, 2);
1008  ASSERT_POINT_NEAR(result, expected);
1009 }
1010 
1011 TEST(GeometryTest, Vector3Min) {
1012  Vector3 p(1, 2, 3);
1013  Vector3 result = p.Min({0, 10, 2});
1014  Vector3 expected(0, 2, 2);
1015  ASSERT_VECTOR3_NEAR(result, expected);
1016 }
1017 
1018 TEST(GeometryTest, Vector4Min) {
1019  Vector4 p(1, 2, 3, 4);
1020  Vector4 result = p.Min({0, 10, 2, 1});
1021  Vector4 expected(0, 2, 2, 1);
1022  ASSERT_VECTOR4_NEAR(result, expected);
1023 }
1024 
1025 TEST(GeometryTest, PointMax) {
1026  Point p(1, 2);
1027  Point result = p.Max({0, 10});
1028  Point expected(1, 10);
1029  ASSERT_POINT_NEAR(result, expected);
1030 }
1031 
1032 TEST(GeometryTest, Vector3Max) {
1033  Vector3 p(1, 2, 3);
1034  Vector3 result = p.Max({0, 10, 2});
1035  Vector3 expected(1, 10, 3);
1036  ASSERT_VECTOR3_NEAR(result, expected);
1037 }
1038 
1039 TEST(GeometryTest, Vector4Max) {
1040  Vector4 p(1, 2, 3, 4);
1041  Vector4 result = p.Max({0, 10, 2, 1});
1042  Vector4 expected(1, 10, 3, 4);
1043  ASSERT_VECTOR4_NEAR(result, expected);
1044 }
1045 
1046 TEST(GeometryTest, PointFloor) {
1047  Point p(1.5, 2.3);
1048  Point result = p.Floor();
1049  Point expected(1, 2);
1050  ASSERT_POINT_NEAR(result, expected);
1051 }
1052 
1053 TEST(GeometryTest, Vector3Floor) {
1054  Vector3 p(1.5, 2.3, 3.9);
1055  Vector3 result = p.Floor();
1056  Vector3 expected(1, 2, 3);
1057  ASSERT_VECTOR3_NEAR(result, expected);
1058 }
1059 
1060 TEST(GeometryTest, Vector4Floor) {
1061  Vector4 p(1.5, 2.3, 3.9, 4.0);
1062  Vector4 result = p.Floor();
1063  Vector4 expected(1, 2, 3, 4);
1064  ASSERT_VECTOR4_NEAR(result, expected);
1065 }
1066 
1067 TEST(GeometryTest, PointCeil) {
1068  Point p(1.5, 2.3);
1069  Point result = p.Ceil();
1070  Point expected(2, 3);
1071  ASSERT_POINT_NEAR(result, expected);
1072 }
1073 
1074 TEST(GeometryTest, Vector3Ceil) {
1075  Vector3 p(1.5, 2.3, 3.9);
1076  Vector3 result = p.Ceil();
1077  Vector3 expected(2, 3, 4);
1078  ASSERT_VECTOR3_NEAR(result, expected);
1079 }
1080 
1081 TEST(GeometryTest, Vector4Ceil) {
1082  Vector4 p(1.5, 2.3, 3.9, 4.0);
1083  Vector4 result = p.Ceil();
1084  Vector4 expected(2, 3, 4, 4);
1085  ASSERT_VECTOR4_NEAR(result, expected);
1086 }
1087 
1088 TEST(GeometryTest, PointRound) {
1089  Point p(1.5, 2.3);
1090  Point result = p.Round();
1091  Point expected(2, 2);
1092  ASSERT_POINT_NEAR(result, expected);
1093 }
1094 
1095 TEST(GeometryTest, Vector3Round) {
1096  Vector3 p(1.5, 2.3, 3.9);
1097  Vector3 result = p.Round();
1098  Vector3 expected(2, 2, 4);
1099  ASSERT_VECTOR3_NEAR(result, expected);
1100 }
1101 
1102 TEST(GeometryTest, Vector4Round) {
1103  Vector4 p(1.5, 2.3, 3.9, 4.0);
1104  Vector4 result = p.Round();
1105  Vector4 expected(2, 2, 4, 4);
1106  ASSERT_VECTOR4_NEAR(result, expected);
1107 }
1108 
1109 TEST(GeometryTest, PointLerp) {
1110  Point p(1, 2);
1111  Point result = p.Lerp({5, 10}, 0.75);
1112  Point expected(4, 8);
1113  ASSERT_POINT_NEAR(result, expected);
1114 }
1115 
1116 TEST(GeometryTest, Vector3Lerp) {
1117  Vector3 p(1, 2, 3);
1118  Vector3 result = p.Lerp({5, 10, 15}, 0.75);
1119  Vector3 expected(4, 8, 12);
1120  ASSERT_VECTOR3_NEAR(result, expected);
1121 }
1122 
1123 TEST(GeometryTest, Vector4Lerp) {
1124  Vector4 p(1, 2, 3, 4);
1125  Vector4 result = p.Lerp({5, 10, 15, 20}, 0.75);
1126  Vector4 expected(4, 8, 12, 16);
1127  ASSERT_VECTOR4_NEAR(result, expected);
1128 }
1129 
1130 TEST(GeometryTest, SeparatedVector2NormalizesWithConstructor) {
1131  SeparatedVector2 v(Vector2(10, 0));
1133  ASSERT_NEAR(v.magnitude, 10, kEhCloseEnough);
1134 }
1135 
1136 TEST(GeometryTest, SeparatedVector2GetVector) {
1137  SeparatedVector2 v(Vector2(10, 0));
1138  ASSERT_POINT_NEAR(v.GetVector(), Vector2(10, 0));
1139 }
1140 
1141 TEST(GeometryTest, SeparatedVector2GetAlignment) {
1142  // Parallel
1143  {
1144  SeparatedVector2 v(Vector2(10, 0));
1145  Scalar actual = v.GetAlignment(SeparatedVector2(Vector2(5, 0)));
1146  ASSERT_NEAR(actual, 1, kEhCloseEnough);
1147  }
1148 
1149  // Perpendicular
1150  {
1151  SeparatedVector2 v(Vector2(10, 0));
1152  Scalar actual = v.GetAlignment(SeparatedVector2(Vector2(0, 5)));
1153  ASSERT_NEAR(actual, 0, kEhCloseEnough);
1154  }
1155 
1156  // Opposite parallel
1157  {
1158  SeparatedVector2 v(Vector2(0, 10));
1159  Scalar actual = v.GetAlignment(SeparatedVector2(Vector2(0, -5)));
1160  ASSERT_NEAR(actual, -1, kEhCloseEnough);
1161  }
1162 }
1163 
1164 TEST(GeometryTest, SeparatedVector2AngleTo) {
1165  {
1166  SeparatedVector2 v(Vector2(10, 0));
1167  Radians actual = v.AngleTo(SeparatedVector2(Vector2(5, 0)));
1168  Radians expected = Radians{0};
1169  ASSERT_NEAR(actual.radians, expected.radians, kEhCloseEnough);
1170  }
1171 
1172  {
1173  SeparatedVector2 v(Vector2(10, 0));
1174  Radians actual = v.AngleTo(SeparatedVector2(Vector2(0, -5)));
1175  Radians expected = Radians{-kPi / 2};
1176  ASSERT_NEAR(actual.radians, expected.radians, kEhCloseEnough);
1177  }
1178 }
1179 
1180 TEST(GeometryTest, CanUseVector3AssignmentOperators) {
1181  {
1182  Vector3 p(1, 2, 4);
1183  p += Vector3(1, 2, 4);
1184  ASSERT_EQ(p.x, 2u);
1185  ASSERT_EQ(p.y, 4u);
1186  ASSERT_EQ(p.z, 8u);
1187  }
1188 
1189  {
1190  Vector3 p(3, 6, 8);
1191  p -= Vector3(1, 2, 3);
1192  ASSERT_EQ(p.x, 2u);
1193  ASSERT_EQ(p.y, 4u);
1194  ASSERT_EQ(p.z, 5u);
1195  }
1196 
1197  {
1198  Vector3 p(1, 2, 3);
1199  p *= Vector3(2, 3, 4);
1200  ASSERT_EQ(p.x, 2u);
1201  ASSERT_EQ(p.y, 6u);
1202  ASSERT_EQ(p.z, 12u);
1203  }
1204 
1205  {
1206  Vector3 p(1, 2, 3);
1207  p *= 2;
1208  ASSERT_EQ(p.x, 2u);
1209  ASSERT_EQ(p.y, 4u);
1210  ASSERT_EQ(p.z, 6u);
1211  }
1212 
1213  {
1214  Vector3 p(2, 6, 12);
1215  p /= Vector3(2, 3, 4);
1216  ASSERT_EQ(p.x, 1u);
1217  ASSERT_EQ(p.y, 2u);
1218  ASSERT_EQ(p.z, 3u);
1219  }
1220 
1221  {
1222  Vector3 p(2, 6, 12);
1223  p /= 2;
1224  ASSERT_EQ(p.x, 1u);
1225  ASSERT_EQ(p.y, 3u);
1226  ASSERT_EQ(p.z, 6u);
1227  }
1228 }
1229 
1230 TEST(GeometryTest, CanPerformAlgebraicVector3Ops) {
1231  {
1232  Vector3 p1(1, 2, 3);
1233  Vector3 p2 = p1 + Vector3(1, 2, 3);
1234  ASSERT_EQ(p2.x, 2u);
1235  ASSERT_EQ(p2.y, 4u);
1236  ASSERT_EQ(p2.z, 6u);
1237  }
1238 
1239  {
1240  Vector3 p1(3, 6, 9);
1241  Vector3 p2 = p1 - Vector3(1, 2, 3);
1242  ASSERT_EQ(p2.x, 2u);
1243  ASSERT_EQ(p2.y, 4u);
1244  ASSERT_EQ(p2.z, 6u);
1245  }
1246 
1247  {
1248  Vector3 p1(1, 2, 3);
1249  Vector3 p2 = p1 * Vector3(2, 3, 4);
1250  ASSERT_EQ(p2.x, 2u);
1251  ASSERT_EQ(p2.y, 6u);
1252  ASSERT_EQ(p2.z, 12u);
1253  }
1254 
1255  {
1256  Vector3 p1(2, 6, 12);
1257  Vector3 p2 = p1 / Vector3(2, 3, 4);
1258  ASSERT_EQ(p2.x, 1u);
1259  ASSERT_EQ(p2.y, 2u);
1260  ASSERT_EQ(p2.z, 3u);
1261  }
1262 }
1263 
1264 TEST(GeometryTest, CanPerformAlgebraicVector3OpsWithArithmeticTypes) {
1265  // LHS
1266  {
1267  Vector3 p1(1, 2, 3);
1268  Vector3 p2 = p1 + 2.0f;
1269  ASSERT_EQ(p2.x, 3);
1270  ASSERT_EQ(p2.y, 4);
1271  ASSERT_EQ(p2.z, 5);
1272  }
1273 
1274  {
1275  Vector3 p1(1, 2, 3);
1276  Vector3 p2 = p1 - 2.0f;
1277  ASSERT_EQ(p2.x, -1);
1278  ASSERT_EQ(p2.y, 0);
1279  ASSERT_EQ(p2.z, 1);
1280  }
1281 
1282  {
1283  Vector3 p1(1, 2, 3);
1284  Vector3 p2 = p1 * 2.0f;
1285  ASSERT_EQ(p2.x, 2);
1286  ASSERT_EQ(p2.y, 4);
1287  ASSERT_EQ(p2.z, 6);
1288  }
1289 
1290  {
1291  Vector3 p1(2, 6, 12);
1292  Vector3 p2 = p1 / 2.0f;
1293  ASSERT_EQ(p2.x, 1);
1294  ASSERT_EQ(p2.y, 3);
1295  ASSERT_EQ(p2.z, 6);
1296  }
1297 
1298  // RHS
1299  {
1300  Vector3 p1(1, 2, 3);
1301  Vector3 p2 = 2.0f + p1;
1302  ASSERT_EQ(p2.x, 3);
1303  ASSERT_EQ(p2.y, 4);
1304  ASSERT_EQ(p2.z, 5);
1305  }
1306 
1307  {
1308  Vector3 p1(1, 2, 3);
1309  Vector3 p2 = 2.0f - p1;
1310  ASSERT_EQ(p2.x, 1);
1311  ASSERT_EQ(p2.y, 0);
1312  ASSERT_EQ(p2.z, -1);
1313  }
1314 
1315  {
1316  Vector3 p1(1, 2, 3);
1317  Vector3 p2 = 2.0f * p1;
1318  ASSERT_EQ(p2.x, 2);
1319  ASSERT_EQ(p2.y, 4);
1320  ASSERT_EQ(p2.z, 6);
1321  }
1322 
1323  {
1324  Vector3 p1(2, 6, 12);
1325  Vector3 p2 = 12.0f / p1;
1326  ASSERT_EQ(p2.x, 6);
1327  ASSERT_EQ(p2.y, 2);
1328  ASSERT_EQ(p2.z, 1);
1329  }
1330 }
1331 
1332 TEST(GeometryTest, ColorPremultiply) {
1333  {
1334  Color a(1.0, 0.5, 0.2, 0.5);
1335  Color premultiplied = a.Premultiply();
1336  Color expected = Color(0.5, 0.25, 0.1, 0.5);
1337  ASSERT_COLOR_NEAR(premultiplied, expected);
1338  }
1339 
1340  {
1341  Color a(0.5, 0.25, 0.1, 0.5);
1342  Color unpremultiplied = a.Unpremultiply();
1343  Color expected = Color(1.0, 0.5, 0.2, 0.5);
1344  ASSERT_COLOR_NEAR(unpremultiplied, expected);
1345  }
1346 
1347  {
1348  Color a(0.5, 0.25, 0.1, 0.0);
1349  Color unpremultiplied = a.Unpremultiply();
1350  Color expected = Color(0.0, 0.0, 0.0, 0.0);
1351  ASSERT_COLOR_NEAR(unpremultiplied, expected);
1352  }
1353 }
1354 
1355 TEST(GeometryTest, ColorR8G8B8A8) {
1356  {
1357  Color a(1.0, 0.5, 0.2, 0.5);
1358  std::array<uint8_t, 4> expected = {255, 128, 51, 128};
1359  ASSERT_ARRAY_4_NEAR(a.ToR8G8B8A8(), expected);
1360  }
1361 
1362  {
1363  Color a(0.0, 0.0, 0.0, 0.0);
1364  std::array<uint8_t, 4> expected = {0, 0, 0, 0};
1365  ASSERT_ARRAY_4_NEAR(a.ToR8G8B8A8(), expected);
1366  }
1367 
1368  {
1369  Color a(1.0, 1.0, 1.0, 1.0);
1370  std::array<uint8_t, 4> expected = {255, 255, 255, 255};
1371  ASSERT_ARRAY_4_NEAR(a.ToR8G8B8A8(), expected);
1372  }
1373 }
1374 
1375 TEST(GeometryTest, ColorLerp) {
1376  {
1377  Color a(0.0, 0.0, 0.0, 0.0);
1378  Color b(1.0, 1.0, 1.0, 1.0);
1379 
1380  ASSERT_COLOR_NEAR(Color::Lerp(a, b, 0.5), Color(0.5, 0.5, 0.5, 0.5));
1381  ASSERT_COLOR_NEAR(Color::Lerp(a, b, 0.0), a);
1382  ASSERT_COLOR_NEAR(Color::Lerp(a, b, 1.0), b);
1383  ASSERT_COLOR_NEAR(Color::Lerp(a, b, 0.2), Color(0.2, 0.2, 0.2, 0.2));
1384  }
1385 
1386  {
1387  Color a(0.2, 0.4, 1.0, 0.5);
1388  Color b(0.4, 1.0, 0.2, 0.3);
1389 
1390  ASSERT_COLOR_NEAR(Color::Lerp(a, b, 0.5), Color(0.3, 0.7, 0.6, 0.4));
1391  ASSERT_COLOR_NEAR(Color::Lerp(a, b, 0.0), a);
1392  ASSERT_COLOR_NEAR(Color::Lerp(a, b, 1.0), b);
1393  ASSERT_COLOR_NEAR(Color::Lerp(a, b, 0.2), Color(0.24, 0.52, 0.84, 0.46));
1394  }
1395 }
1396 
1397 TEST(GeometryTest, ColorClamp01) {
1398  {
1399  Color result = Color(0.5, 0.5, 0.5, 0.5).Clamp01();
1400  Color expected = Color(0.5, 0.5, 0.5, 0.5);
1401  ASSERT_COLOR_NEAR(result, expected);
1402  }
1403 
1404  {
1405  Color result = Color(-1, -1, -1, -1).Clamp01();
1406  Color expected = Color(0, 0, 0, 0);
1407  ASSERT_COLOR_NEAR(result, expected);
1408  }
1409 
1410  {
1411  Color result = Color(2, 2, 2, 2).Clamp01();
1412  Color expected = Color(1, 1, 1, 1);
1413  ASSERT_COLOR_NEAR(result, expected);
1414  }
1415 }
1416 
1417 TEST(GeometryTest, ColorMakeRGBA8) {
1418  {
1419  Color a = Color::MakeRGBA8(0, 0, 0, 0);
1421  ASSERT_COLOR_NEAR(a, b);
1422  }
1423 
1424  {
1425  Color a = Color::MakeRGBA8(255, 255, 255, 255);
1426  Color b = Color::White();
1427  ASSERT_COLOR_NEAR(a, b);
1428  }
1429 
1430  {
1431  Color a = Color::MakeRGBA8(63, 127, 191, 127);
1432  Color b(0.247059, 0.498039, 0.74902, 0.498039);
1433  ASSERT_COLOR_NEAR(a, b);
1434  }
1435 }
1436 
1437 TEST(GeometryTest, ColorApplyColorMatrix) {
1438  {
1439  ColorMatrix color_matrix = {
1440  1, 1, 1, 1, 1, //
1441  1, 1, 1, 1, 1, //
1442  1, 1, 1, 1, 1, //
1443  1, 1, 1, 1, 1, //
1444  };
1445  auto result = Color::White().ApplyColorMatrix(color_matrix);
1446  auto expected = Color(1, 1, 1, 1);
1447  ASSERT_COLOR_NEAR(result, expected);
1448  }
1449 
1450  {
1451  ColorMatrix color_matrix = {
1452  0.1, 0, 0, 0, 0.01, //
1453  0, 0.2, 0, 0, 0.02, //
1454  0, 0, 0.3, 0, 0.03, //
1455  0, 0, 0, 0.4, 0.04, //
1456  };
1457  auto result = Color::White().ApplyColorMatrix(color_matrix);
1458  auto expected = Color(0.11, 0.22, 0.33, 0.44);
1459  ASSERT_COLOR_NEAR(result, expected);
1460  }
1461 }
1462 
1463 TEST(GeometryTest, ColorLinearToSRGB) {
1464  {
1465  auto result = Color::White().LinearToSRGB();
1466  auto expected = Color(1, 1, 1, 1);
1467  ASSERT_COLOR_NEAR(result, expected);
1468  }
1469 
1470  {
1471  auto result = Color::BlackTransparent().LinearToSRGB();
1472  auto expected = Color(0, 0, 0, 0);
1473  ASSERT_COLOR_NEAR(result, expected);
1474  }
1475 
1476  {
1477  auto result = Color(0.2, 0.4, 0.6, 0.8).LinearToSRGB();
1478  auto expected = Color(0.484529, 0.665185, 0.797738, 0.8);
1479  ASSERT_COLOR_NEAR(result, expected);
1480  }
1481 }
1482 
1483 TEST(GeometryTest, ColorSRGBToLinear) {
1484  {
1485  auto result = Color::White().SRGBToLinear();
1486  auto expected = Color(1, 1, 1, 1);
1487  ASSERT_COLOR_NEAR(result, expected);
1488  }
1489 
1490  {
1491  auto result = Color::BlackTransparent().SRGBToLinear();
1492  auto expected = Color(0, 0, 0, 0);
1493  ASSERT_COLOR_NEAR(result, expected);
1494  }
1495 
1496  {
1497  auto result = Color(0.2, 0.4, 0.6, 0.8).SRGBToLinear();
1498  auto expected = Color(0.0331048, 0.132868, 0.318547, 0.8);
1499  ASSERT_COLOR_NEAR(result, expected);
1500  }
1501 }
1502 
1504  static constexpr Color kDestinationColor =
1506  static constexpr Color kSourceColors[] = {Color::White().WithAlpha(0.75),
1507  Color::LimeGreen().WithAlpha(0.75),
1508  Color::Black().WithAlpha(0.75)};
1509 
1510  static const std::map<BlendMode, Color>
1512 };
1513 
1514 // THIS RESULT TABLE IS GENERATED!
1515 //
1516 // Uncomment the `GenerateColorBlendResults` test below to print a new table
1517 // after making changes to `Color::Blend`.
1518 const std::map<BlendMode, Color> ColorBlendTestData::kExpectedResults[sizeof(
1520  {
1521  {BlendMode::kClear, {0, 0, 0, 0}},
1522  {BlendMode::kSource, {1, 1, 1, 0.75}},
1523  {BlendMode::kDestination, {0.392157, 0.584314, 0.929412, 0.75}},
1524  {BlendMode::kSourceOver, {0.878431, 0.916863, 0.985882, 0.9375}},
1525  {BlendMode::kDestinationOver, {0.513726, 0.667451, 0.943529, 0.9375}},
1526  {BlendMode::kSourceIn, {1, 1, 1, 0.5625}},
1527  {BlendMode::kDestinationIn, {0.392157, 0.584314, 0.929412, 0.5625}},
1528  {BlendMode::kSourceOut, {1, 1, 1, 0.1875}},
1529  {BlendMode::kDestinationOut, {0.392157, 0.584314, 0.929412, 0.1875}},
1530  {BlendMode::kSourceATop, {0.848039, 0.896078, 0.982353, 0.75}},
1531  {BlendMode::kDestinationATop, {0.544118, 0.688235, 0.947059, 0.75}},
1532  {BlendMode::kXor, {0.696078, 0.792157, 0.964706, 0.375}},
1533  {BlendMode::kPlus, {1, 1, 1, 1}},
1534  {BlendMode::kModulate, {0.392157, 0.584314, 0.929412, 0.5625}},
1535  {BlendMode::kScreen, {0.878431, 0.916863, 0.985882, 0.9375}},
1536  {BlendMode::kOverlay, {0.74902, 0.916863, 0.985882, 0.9375}},
1537  {BlendMode::kDarken, {0.513726, 0.667451, 0.943529, 0.9375}},
1538  {BlendMode::kLighten, {0.878431, 0.916863, 0.985882, 0.9375}},
1539  {BlendMode::kColorDodge, {0.878431, 0.916863, 0.985882, 0.9375}},
1540  {BlendMode::kColorBurn, {0.513725, 0.667451, 0.943529, 0.9375}},
1541  {BlendMode::kHardLight, {0.878431, 0.916863, 0.985882, 0.9375}},
1542  {BlendMode::kSoftLight, {0.654166, 0.775505, 0.964318, 0.9375}},
1543  {BlendMode::kDifference, {0.643137, 0.566275, 0.428235, 0.9375}},
1544  {BlendMode::kExclusion, {0.643137, 0.566275, 0.428235, 0.9375}},
1545  {BlendMode::kMultiply, {0.513726, 0.667451, 0.943529, 0.9375}},
1546  {BlendMode::kHue, {0.617208, 0.655639, 0.724659, 0.9375}},
1547  {BlendMode::kSaturation, {0.617208, 0.655639, 0.724659, 0.9375}},
1548  {BlendMode::kColor, {0.617208, 0.655639, 0.724659, 0.9375}},
1549  {BlendMode::kLuminosity, {0.878431, 0.916863, 0.985882, 0.9375}},
1550  },
1551  {
1552  {BlendMode::kClear, {0, 0, 0, 0}},
1553  {BlendMode::kSource, {0.196078, 0.803922, 0.196078, 0.75}},
1554  {BlendMode::kDestination, {0.392157, 0.584314, 0.929412, 0.75}},
1555  {BlendMode::kSourceOver, {0.235294, 0.76, 0.342745, 0.9375}},
1556  {BlendMode::kDestinationOver, {0.352941, 0.628235, 0.782745, 0.9375}},
1557  {BlendMode::kSourceIn, {0.196078, 0.803922, 0.196078, 0.5625}},
1558  {BlendMode::kDestinationIn, {0.392157, 0.584314, 0.929412, 0.5625}},
1559  {BlendMode::kSourceOut, {0.196078, 0.803922, 0.196078, 0.1875}},
1560  {BlendMode::kDestinationOut, {0.392157, 0.584314, 0.929412, 0.1875}},
1561  {BlendMode::kSourceATop, {0.245098, 0.74902, 0.379412, 0.75}},
1562  {BlendMode::kDestinationATop, {0.343137, 0.639216, 0.746078, 0.75}},
1563  {BlendMode::kXor, {0.294118, 0.694118, 0.562745, 0.375}},
1564  {BlendMode::kPlus, {0.441176, 1, 0.844118, 1}},
1565  {BlendMode::kModulate, {0.0768935, 0.469742, 0.182238, 0.5625}},
1566  {BlendMode::kScreen, {0.424452, 0.828743, 0.79105, 0.9375}},
1567  {BlendMode::kOverlay, {0.209919, 0.779839, 0.757001, 0.9375}},
1568  {BlendMode::kDarken, {0.235294, 0.628235, 0.342745, 0.9375}},
1569  {BlendMode::kLighten, {0.352941, 0.76, 0.782745, 0.9375}},
1570  {BlendMode::kColorDodge, {0.41033, 0.877647, 0.825098, 0.9375}},
1571  {BlendMode::kColorBurn, {0.117647, 0.567403, 0.609098, 0.9375}},
1572  {BlendMode::kHardLight, {0.209919, 0.779839, 0.443783, 0.9375}},
1573  {BlendMode::kSoftLight, {0.266006, 0.693915, 0.758818, 0.9375}},
1574  {BlendMode::kDifference, {0.235294, 0.409412, 0.665098, 0.9375}},
1575  {BlendMode::kExclusion, {0.378316, 0.546897, 0.681707, 0.9375}},
1576  {BlendMode::kMultiply, {0.163783, 0.559493, 0.334441, 0.9375}},
1577  {BlendMode::kHue, {0.266235, 0.748588, 0.373686, 0.9375}},
1578  {BlendMode::kSaturation, {0.339345, 0.629787, 0.811502, 0.9375}},
1579  {BlendMode::kColor, {0.241247, 0.765953, 0.348698, 0.9375}},
1580  {BlendMode::kLuminosity, {0.346988, 0.622282, 0.776792, 0.9375}},
1581  },
1582  {
1583  {BlendMode::kClear, {0, 0, 0, 0}},
1584  {BlendMode::kSource, {0, 0, 0, 0.75}},
1585  {BlendMode::kDestination, {0.392157, 0.584314, 0.929412, 0.75}},
1586  {BlendMode::kSourceOver, {0.0784314, 0.116863, 0.185882, 0.9375}},
1587  {BlendMode::kDestinationOver, {0.313726, 0.467451, 0.743529, 0.9375}},
1588  {BlendMode::kSourceIn, {0, 0, 0, 0.5625}},
1589  {BlendMode::kDestinationIn, {0.392157, 0.584314, 0.929412, 0.5625}},
1590  {BlendMode::kSourceOut, {0, 0, 0, 0.1875}},
1591  {BlendMode::kDestinationOut, {0.392157, 0.584314, 0.929412, 0.1875}},
1592  {BlendMode::kSourceATop, {0.0980392, 0.146078, 0.232353, 0.75}},
1593  {BlendMode::kDestinationATop, {0.294118, 0.438235, 0.697059, 0.75}},
1594  {BlendMode::kXor, {0.196078, 0.292157, 0.464706, 0.375}},
1595  {BlendMode::kPlus, {0.294118, 0.438235, 0.697059, 1}},
1596  {BlendMode::kModulate, {0, 0, 0, 0.5625}},
1597  {BlendMode::kScreen, {0.313726, 0.467451, 0.743529, 0.9375}},
1598  {BlendMode::kOverlay, {0.0784314, 0.218039, 0.701176, 0.9375}},
1599  {BlendMode::kDarken, {0.0784314, 0.116863, 0.185882, 0.9375}},
1600  {BlendMode::kLighten, {0.313726, 0.467451, 0.743529, 0.9375}},
1601  {BlendMode::kColorDodge, {0.313726, 0.467451, 0.743529, 0.9375}},
1602  {BlendMode::kColorBurn, {0.0784314, 0.116863, 0.185882, 0.9375}},
1603  {BlendMode::kHardLight, {0.0784314, 0.116863, 0.185882, 0.9375}},
1604  {BlendMode::kSoftLight, {0.170704, 0.321716, 0.704166, 0.9375}},
1605  {BlendMode::kDifference, {0.313726, 0.467451, 0.743529, 0.9375}},
1606  {BlendMode::kExclusion, {0.313726, 0.467451, 0.743529, 0.9375}},
1607  {BlendMode::kMultiply, {0.0784314, 0.116863, 0.185882, 0.9375}},
1608  {BlendMode::kHue, {0.417208, 0.455639, 0.524659, 0.9375}},
1609  {BlendMode::kSaturation, {0.417208, 0.455639, 0.524659, 0.9375}},
1610  {BlendMode::kColor, {0.417208, 0.455639, 0.524659, 0.9375}},
1611  {BlendMode::kLuminosity, {0.0784314, 0.116863, 0.185882, 0.9375}},
1612  },
1613 };
1614 
1615 /// To print a new ColorBlendTestData::kExpectedResults table, uncomment this
1616 /// test and run with:
1617 /// --gtest_filter="GeometryTest.GenerateColorBlendResults"
1618 /*
1619 TEST(GeometryTest, GenerateColorBlendResults) {
1620  auto& o = std::cout;
1621  using BlendT = std::underlying_type_t<BlendMode>;
1622  o << "{";
1623  for (const auto& source : ColorBlendTestData::kSourceColors) {
1624  o << "{";
1625  for (BlendT blend_i = 0;
1626  blend_i < static_cast<BlendT>(BlendMode::kLast) + 1; blend_i++) {
1627  auto blend = static_cast<BlendMode>(blend_i);
1628  Color c = ColorBlendTestData::kDestinationColor.Blend(source, blend);
1629  o << "{ BlendMode::k" << BlendModeToString(blend) << ", ";
1630  o << "{" << c.red << "," << c.green << "," << c.blue << "," << c.alpha
1631  << "}";
1632  o << "}," << std::endl;
1633  }
1634  o << "},";
1635  }
1636  o << "};" << std::endl;
1637 }
1638 */
1639 
1640 #define _BLEND_MODE_RESULT_CHECK(blend_mode) \
1641  expected = ColorBlendTestData::kExpectedResults[source_i] \
1642  .find(BlendMode::k##blend_mode) \
1643  ->second; \
1644  EXPECT_COLOR_NEAR(dst.Blend(src, BlendMode::k##blend_mode), expected);
1645 
1646 TEST(GeometryTest, ColorBlendReturnsExpectedResults) {
1648  for (size_t source_i = 0;
1649  source_i < sizeof(ColorBlendTestData::kSourceColors) / sizeof(Color);
1650  source_i++) {
1651  Color src = ColorBlendTestData::kSourceColors[source_i];
1652 
1653  Color expected;
1655  }
1656 }
1657 
1658 #define _BLEND_MODE_NAME_CHECK(blend_mode) \
1659  case BlendMode::k##blend_mode: \
1660  ASSERT_STREQ(result, #blend_mode); \
1661  break;
1662 
1663 TEST(GeometryTest, BlendModeToString) {
1664  using BlendT = std::underlying_type_t<BlendMode>;
1665  for (BlendT i = 0; i <= static_cast<BlendT>(BlendMode::kLast); i++) {
1666  auto mode = static_cast<BlendMode>(i);
1667  auto result = BlendModeToString(mode);
1669  }
1670 }
1671 
1672 TEST(GeometryTest, CanConvertBetweenDegressAndRadians) {
1673  {
1674  auto deg = Degrees{90.0};
1675  Radians rad = deg;
1676  ASSERT_FLOAT_EQ(rad.radians, kPiOver2);
1677  }
1678 }
1679 
1680 TEST(GeometryTest, MatrixPrinting) {
1681  {
1682  std::stringstream stream;
1683  Matrix m;
1684  stream << m;
1685  ASSERT_EQ(stream.str(), R"((
1686  1.000000, 0.000000, 0.000000, 0.000000,
1687  0.000000, 1.000000, 0.000000, 0.000000,
1688  0.000000, 0.000000, 1.000000, 0.000000,
1689  0.000000, 0.000000, 0.000000, 1.000000,
1690 ))");
1691  }
1692 
1693  {
1694  std::stringstream stream;
1695  Matrix m = Matrix::MakeTranslation(Vector3(10, 20, 30));
1696  stream << m;
1697 
1698  ASSERT_EQ(stream.str(), R"((
1699  1.000000, 0.000000, 0.000000, 10.000000,
1700  0.000000, 1.000000, 0.000000, 20.000000,
1701  0.000000, 0.000000, 1.000000, 30.000000,
1702  0.000000, 0.000000, 0.000000, 1.000000,
1703 ))");
1704  }
1705 }
1706 
1707 TEST(GeometryTest, PointPrinting) {
1708  {
1709  std::stringstream stream;
1710  Point m;
1711  stream << m;
1712  ASSERT_EQ(stream.str(), "(0, 0)");
1713  }
1714 
1715  {
1716  std::stringstream stream;
1717  Point m(13, 37);
1718  stream << m;
1719  ASSERT_EQ(stream.str(), "(13, 37)");
1720  }
1721 }
1722 
1723 TEST(GeometryTest, Vector3Printing) {
1724  {
1725  std::stringstream stream;
1726  Vector3 m;
1727  stream << m;
1728  ASSERT_EQ(stream.str(), "(0, 0, 0)");
1729  }
1730 
1731  {
1732  std::stringstream stream;
1733  Vector3 m(1, 2, 3);
1734  stream << m;
1735  ASSERT_EQ(stream.str(), "(1, 2, 3)");
1736  }
1737 }
1738 
1739 TEST(GeometryTest, Vector4Printing) {
1740  {
1741  std::stringstream stream;
1742  Vector4 m;
1743  stream << m;
1744  ASSERT_EQ(stream.str(), "(0, 0, 0, 1)");
1745  }
1746 
1747  {
1748  std::stringstream stream;
1749  Vector4 m(1, 2, 3, 4);
1750  stream << m;
1751  ASSERT_EQ(stream.str(), "(1, 2, 3, 4)");
1752  }
1753 }
1754 
1755 TEST(GeometryTest, ColorPrinting) {
1756  {
1757  std::stringstream stream;
1758  Color m;
1759  stream << m;
1760  ASSERT_EQ(stream.str(), "(0, 0, 0, 0)");
1761  }
1762 
1763  {
1764  std::stringstream stream;
1765  Color m(1, 2, 3, 4);
1766  stream << m;
1767  ASSERT_EQ(stream.str(), "(1, 2, 3, 4)");
1768  }
1769 }
1770 
1771 TEST(GeometryTest, ToIColor) {
1772  ASSERT_EQ(Color::ToIColor(Color(0, 0, 0, 0)), 0u);
1773  ASSERT_EQ(Color::ToIColor(Color(1.0, 1.0, 1.0, 1.0)), 0xFFFFFFFF);
1774  ASSERT_EQ(Color::ToIColor(Color(0.5, 0.5, 1.0, 1.0)), 0xFF8080FF);
1775 }
1776 
1777 TEST(GeometryTest, Gradient) {
1778  {
1779  // Simple 2 color gradient produces color buffer containing exactly those
1780  // values.
1781  std::vector<Color> colors = {Color::Red(), Color::Blue()};
1782  std::vector<Scalar> stops = {0.0, 1.0};
1783 
1784  auto gradient = CreateGradientBuffer(colors, stops);
1785 
1786  ASSERT_COLOR_BUFFER_NEAR(gradient.color_bytes, colors);
1787  ASSERT_EQ(gradient.texture_size, 2u);
1788  }
1789 
1790  {
1791  // Gradient with duplicate stops does not create an empty texture.
1792  std::vector<Color> colors = {Color::Red(), Color::Yellow(), Color::Black(),
1793  Color::Blue()};
1794  std::vector<Scalar> stops = {0.0, 0.25, 0.25, 1.0};
1795 
1796  auto gradient = CreateGradientBuffer(colors, stops);
1797  ASSERT_EQ(gradient.texture_size, 5u);
1798  }
1799 
1800  {
1801  // Simple N color gradient produces color buffer containing exactly those
1802  // values.
1803  std::vector<Color> colors = {Color::Red(), Color::Blue(), Color::Green(),
1804  Color::White()};
1805  std::vector<Scalar> stops = {0.0, 0.33, 0.66, 1.0};
1806 
1807  auto gradient = CreateGradientBuffer(colors, stops);
1808 
1809  ASSERT_COLOR_BUFFER_NEAR(gradient.color_bytes, colors);
1810  ASSERT_EQ(gradient.texture_size, 4u);
1811  }
1812 
1813  {
1814  // Gradient with color stops will lerp and scale buffer.
1815  std::vector<Color> colors = {Color::Red(), Color::Blue(), Color::Green()};
1816  std::vector<Scalar> stops = {0.0, 0.25, 1.0};
1817 
1818  auto gradient = CreateGradientBuffer(colors, stops);
1819 
1820  std::vector<Color> lerped_colors = {
1821  Color::Red(),
1822  Color::Blue(),
1823  Color::Lerp(Color::Blue(), Color::Green(), 0.3333),
1824  Color::Lerp(Color::Blue(), Color::Green(), 0.6666),
1825  Color::Green(),
1826  };
1827  ASSERT_COLOR_BUFFER_NEAR(gradient.color_bytes, lerped_colors);
1828  ASSERT_EQ(gradient.texture_size, 5u);
1829  }
1830 
1831  {
1832  // Gradient size is capped at 1024.
1833  std::vector<Color> colors = {};
1834  std::vector<Scalar> stops = {};
1835  for (auto i = 0u; i < 1025; i++) {
1836  colors.push_back(Color::Blue());
1837  stops.push_back(i / 1025.0);
1838  }
1839 
1840  auto gradient = CreateGradientBuffer(colors, stops);
1841 
1842  ASSERT_EQ(gradient.texture_size, 1024u);
1843  ASSERT_EQ(gradient.color_bytes.size(), 1024u * 4);
1844  }
1845 }
1846 
1847 TEST(GeometryTest, HalfConversions) {
1848 #if defined(FML_OS_MACOSX) || defined(FML_OS_IOS) || \
1849  defined(FML_OS_IOS_SIMULATOR)
1850  ASSERT_EQ(ScalarToHalf(0.0), 0.0f16);
1851  ASSERT_EQ(ScalarToHalf(0.05), 0.05f16);
1852  ASSERT_EQ(ScalarToHalf(2.43), 2.43f16);
1853  ASSERT_EQ(ScalarToHalf(-1.45), -1.45f16);
1854 
1855  // 65504 is the largest possible half.
1856  ASSERT_EQ(ScalarToHalf(65504.0f), 65504.0f16);
1857  ASSERT_EQ(ScalarToHalf(65504.0f + 1), 65504.0f16);
1858 
1859  // Colors
1860  ASSERT_EQ(HalfVector4(Color::Red()),
1861  HalfVector4(1.0f16, 0.0f16, 0.0f16, 1.0f16));
1862  ASSERT_EQ(HalfVector4(Color::Green()),
1863  HalfVector4(0.0f16, 1.0f16, 0.0f16, 1.0f16));
1864  ASSERT_EQ(HalfVector4(Color::Blue()),
1865  HalfVector4(0.0f16, 0.0f16, 1.0f16, 1.0f16));
1866  ASSERT_EQ(HalfVector4(Color::Black().WithAlpha(0)),
1867  HalfVector4(0.0f16, 0.0f16, 0.0f16, 0.0f16));
1868 
1869  ASSERT_EQ(HalfVector3(Vector3(4.0, 6.0, -1.0)),
1870  HalfVector3(4.0f16, 6.0f16, -1.0f16));
1871  ASSERT_EQ(HalfVector2(Vector2(4.0, 6.0)), HalfVector2(4.0f16, 6.0f16));
1872 
1873  ASSERT_EQ(Half(0.5f), Half(0.5f16));
1874  ASSERT_EQ(Half(0.5), Half(0.5f16));
1875  ASSERT_EQ(Half(5), Half(5.0f16));
1876 #else
1877  GTEST_SKIP() << "Half-precision floats (IEEE 754) are not portable and "
1878  "only used on Apple platforms.";
1879 #endif // FML_OS_MACOSX || FML_OS_IOS || FML_OS_IOS_SIMULATOR
1880 }
1881 
1882 } // namespace testing
1883 } // namespace impeller
1884 
1885 // NOLINTEND(bugprone-unchecked-optional-access)
impeller::Matrix::MakeSkew
static constexpr Matrix MakeSkew(Scalar sx, Scalar sy)
Definition: matrix.h:117
impeller::ISize
ISize64 ISize
Definition: size.h:140
_BLEND_MODE_RESULT_CHECK
#define _BLEND_MODE_RESULT_CHECK(blend_mode)
Definition: geometry_unittests.cc:1640
impeller::Color::Blue
static constexpr Color Blue()
Definition: color.h:275
ASSERT_COLOR_NEAR
#define ASSERT_COLOR_NEAR(a, b)
Definition: geometry_asserts.h:192
impeller::Matrix::Decompose
std::optional< MatrixDecomposition > Decompose() const
Definition: matrix.cc:200
impeller::k1OverSqrt2
constexpr float k1OverSqrt2
Definition: constants.h:50
impeller::Matrix::MakeRotationX
static Matrix MakeRotationX(Radians r)
Definition: matrix.h:183
separated_vector.h
impeller::BlendModeToString
const char * BlendModeToString(BlendMode blend_mode)
Definition: color.cc:47
impeller::BlendMode::kDestinationATop
@ kDestinationATop
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:271
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:58
impeller::Color::MakeRGBA8
static constexpr Color MakeRGBA8(uint8_t r, uint8_t g, uint8_t b, uint8_t a)
Definition: color.h:151
impeller::Color
Definition: color.h:123
impeller::Color::Unpremultiply
constexpr Color Unpremultiply() const
Definition: color.h:215
impeller::TPoint::Lerp
constexpr TPoint Lerp(const TPoint &p, Scalar t) const
Definition: point.h:236
impeller::kEhCloseEnough
constexpr float kEhCloseEnough
Definition: constants.h:56
impeller::SeparatedVector2
A Vector2, broken down as a separate magnitude and direction. Assumes that the direction given is nor...
Definition: separated_vector.h:21
impeller::Vector4
Definition: vector.h:232
impeller::BlendMode::kLuminosity
@ kLuminosity
impeller::BlendMode::kSource
@ kSource
impeller::BlendMode::kColorDodge
@ kColorDodge
impeller::Matrix::MakeRotation
static Matrix MakeRotation(Quaternion q)
Definition: matrix.h:126
impeller::BlendMode::kDestination
@ kDestination
impeller::TPoint::Min
constexpr TPoint Min(const TPoint &p) const
Definition: point.h:186
impeller::SeparatedVector2::magnitude
Scalar magnitude
The magnitude of the vector.
Definition: separated_vector.h:26
impeller::BlendMode::kDarken
@ kDarken
impeller::SeparatedVector2::direction
Vector2 direction
The normalized direction of the vector.
Definition: separated_vector.h:23
impeller::TPoint::Round
static constexpr TPoint Round(const TPoint< U > &other)
Definition: point.h:49
impeller::Vector2
Point Vector2
Definition: point.h:331
impeller::BlendMode::kColor
@ kColor
impeller::Matrix::MakeRotationY
static Matrix MakeRotationY(Radians r)
Definition: matrix.h:198
impeller::kPi
constexpr float kPi
Definition: constants.h:26
impeller::BlendMode::kDestinationOver
@ kDestinationOver
impeller::BlendMode::kPlus
@ kPlus
impeller::Color::CornflowerBlue
static constexpr Color CornflowerBlue()
Definition: color.h:341
impeller::BlendMode::kOverlay
@ kOverlay
impeller::Color::Yellow
static constexpr Color Yellow()
Definition: color.h:841
impeller::Radians::radians
Scalar radians
Definition: scalar.h:44
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:193
impeller::Matrix::MakeTranslation
static constexpr Matrix MakeTranslation(const Vector3 &t)
Definition: matrix.h:95
impeller::Color::Clamp01
constexpr Color Clamp01() const
Definition: color.h:235
ASSERT_VECTOR4_NEAR
#define ASSERT_VECTOR4_NEAR(a, b)
Definition: geometry_asserts.h:195
impeller::Vector3::x
Scalar x
Definition: vector.h:23
impeller::TPoint::Floor
constexpr TPoint Floor() const
Definition: point.h:194
impeller::BlendMode::kModulate
@ kModulate
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::BlendMode::kSourceOut
@ kSourceOut
impeller::Matrix::MakeLookAt
static constexpr Matrix MakeLookAt(Vector3 position, Vector3 target, Vector3 up)
Definition: matrix.h:558
impeller::Matrix::MakePerspective
static constexpr Matrix MakePerspective(Radians fov_y, Scalar aspect_ratio, Scalar z_near, Scalar z_far)
Definition: matrix.h:532
impeller::BlendMode::kSaturation
@ kSaturation
impeller::BlendMode::kDifference
@ kDifference
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::BlendMode::kLighten
@ kLighten
impeller::Matrix::Basis
constexpr Matrix Basis() const
The Matrix without its w components (without translation).
Definition: matrix.h:229
impeller::TSize< Scalar >
impeller::Quaternion
Definition: quaternion.h:14
impeller::BlendMode::kSoftLight
@ kSoftLight
impeller::Point
TPoint< Scalar > Point
Definition: point.h:327
impeller::k2Pi
constexpr float k2Pi
Definition: constants.h:29
impeller::BlendMode::kColorBurn
@ kColorBurn
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:232
impeller::BlendMode::kHardLight
@ kHardLight
impeller::Color::ToIColor
static constexpr uint32_t ToIColor(Color color)
Convert this color to a 32-bit representation.
Definition: color.h:158
impeller::SeparatedVector2::GetVector
Vector2 GetVector() const
Returns the vector representation of the vector.
Definition: separated_vector.cc:17
impeller::Color::SRGBToLinear
Color SRGBToLinear() const
Convert the color from sRGB space to linear space.
Definition: color.cc:322
impeller::BlendMode::kClear
@ kClear
impeller::Vector4::Lerp
constexpr Vector4 Lerp(const Vector4 &v, Scalar t) const
Definition: vector.h:309
impeller::testing::ColorBlendTestData::kExpectedResults
static const std::map< BlendMode, Color > kExpectedResults[sizeof(kSourceColors)]
Definition: geometry_unittests.cc:1511
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:277
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:245
impeller::SeparatedVector2::GetAlignment
Scalar GetAlignment(const SeparatedVector2 &other) const
Definition: separated_vector.cc:21
impeller::Color::White
static constexpr Color White()
Definition: color.h:263
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:43
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:1658
impeller::Color::Green
static constexpr Color Green()
Definition: color.h:273
ASSERT_MATRIX_NEAR
#define ASSERT_MATRIX_NEAR(a, b)
Definition: geometry_asserts.h:189
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:190
impeller::Matrix::GetDirectionScale
constexpr Scalar GetDirectionScale(Vector3 direction) const
Definition: matrix.h:321
scalar.h
impeller::MatrixDecomposition::scale
Vector3 scale
Definition: matrix_decomposition.h:17
impeller::BlendMode::kDestinationIn
@ kDestinationIn
impeller::TPoint::Abs
constexpr TPoint Abs() const
Definition: point.h:216
impeller::BlendMode::kExclusion
@ kExclusion
impeller::BlendMode::kDestinationOut
@ kDestinationOut
half.h
impeller::Matrix::MakeRotationZ
static Matrix MakeRotationZ(Radians r)
Definition: matrix.h:213
constants.h
impeller::IPoint
TPoint< int64_t > IPoint
Definition: point.h:328
ASSERT_VECTOR3_NEAR
#define ASSERT_VECTOR3_NEAR(a, b)
Definition: geometry_asserts.h:194
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:269
impeller::Color::Black
static constexpr Color Black()
Definition: color.h:265
impeller::testing::ColorBlendTestData::kSourceColors
static constexpr Color kSourceColors[]
Definition: geometry_unittests.cc:1506
impeller::Vector4::Floor
constexpr Vector4 Floor() const
Definition: vector.h:297
impeller::BlendMode::kSourceIn
@ kSourceIn
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:301
impeller::BlendMode::kScreen
@ kScreen
impeller::ScalarNearlyEqual
constexpr bool ScalarNearlyEqual(Scalar x, Scalar y, Scalar tolerance=kEhCloseEnough)
Definition: scalar.h:35
impeller::Matrix::MakeOrthographic
static constexpr Matrix MakeOrthographic(TSize< T > size)
Definition: matrix.h:523
impeller::testing::ColorBlendTestData
Definition: geometry_unittests.cc:1503
impeller::testing::ColorBlendTestData::kDestinationColor
static constexpr Color kDestinationColor
Definition: geometry_unittests.cc:1504
impeller::Vector3::Min
constexpr Vector3 Min(const Vector3 &p) const
Definition: vector.h:70
impeller::Degrees
Definition: scalar.h:51
color.h
impeller::Color::LimeGreen
static constexpr Color LimeGreen()
Definition: color.h:601
impeller::BlendMode::kLast
@ kLast
impeller::TPoint::Rotate
constexpr TPoint Rotate(const Radians &angle) const
Definition: point.h:226
impeller::TSize::height
Type height
Definition: size.h:23
impeller::BlendMode::kHue
@ kHue
impeller::SeparatedVector2::AngleTo
Radians AngleTo(const SeparatedVector2 &other) const
Returns the scalar angle between the two rays.
Definition: separated_vector.cc:25
impeller::BlendMode::kXor
@ kXor
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:231
impeller::TPoint::Normalize
constexpr TPoint Normalize() const
Definition: point.h:208
impeller::ColorMatrix
Definition: color.h:116
impeller::Color::ApplyColorMatrix
Color ApplyColorMatrix(const ColorMatrix &color_matrix) const
A color filter that transforms colors through a 4x5 color matrix.
Definition: color.cc:301
impeller::Color::LinearToSRGB
Color LinearToSRGB() const
Convert the color from linear space to sRGB space.
Definition: color.cc:311
ASSERT_COLOR_BUFFER_NEAR
#define ASSERT_COLOR_BUFFER_NEAR(a, b)
Definition: geometry_asserts.h:198
impeller
Definition: allocation.cc:12
impeller::Matrix::MakeScale
static constexpr Matrix MakeScale(const Vector3 &s)
Definition: matrix.h:104
impeller::testing::TEST
TEST(AllocationSizeTest, CanCreateTypedAllocations)
Definition: allocation_size_unittests.cc:10
impeller::BlendMode::kSourceATop
@ kSourceATop
impeller::BlendMode::kMultiply
@ kMultiply
impeller::kPiOver4
constexpr float kPiOver4
Definition: constants.h:35
impeller::Color::Premultiply
constexpr Color Premultiply() const
Definition: color.h:211
impeller::Matrix
A 4x4 matrix using column-major storage.
Definition: matrix.h:37
impeller::Vector3
Definition: vector.h:20
size.h
impeller::BlendMode::kSourceOver
@ kSourceOver
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:197
impeller::Vector3::Max
constexpr Vector3 Max(const Vector3 &p) const
Definition: vector.h:74
impeller::Vector4::Ceil
constexpr Vector4 Ceil() const
Definition: vector.h:301