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