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