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 <sstream>
10 #include <type_traits>
11 
12 #include "flutter/fml/build_config.h"
13 #include "flutter/testing/testing.h"
17 #include "impeller/geometry/half.h"
19 #include "impeller/geometry/rect.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}) *
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}) *
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}) *
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}) *
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}) *
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}) *
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}) *
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  {
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}) *
452  Scalar result = m.GetDirectionScale(Vector3{0, 1, 0});
453  ASSERT_FLOAT_EQ(result, 1);
454  }
455 
456  {
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);
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 
1447  static constexpr Color kDestinationColor =
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>;
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;
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);
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