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