| Flutter Impeller |

matrix.h
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 #ifndef FLUTTER_IMPELLER_GEOMETRY_MATRIX_H_
6 #define FLUTTER_IMPELLER_GEOMETRY_MATRIX_H_
7
8 #include <cmath>
9 #include <iomanip>
10 #include <limits>
11 #include <optional>
12 #include <ostream>
13 #include <utility>
14
15 #include "impeller/geometry/matrix_decomposition.h"
16 #include "impeller/geometry/point.h"
17 #include "impeller/geometry/quaternion.h"
18 #include "impeller/geometry/scalar.h"
19 #include "impeller/geometry/shear.h"
20 #include "impeller/geometry/size.h"
21 #include "impeller/geometry/vector.h"
22
23 namespace impeller {
24
25 //------------------------------------------------------------------------------
26 /// @brief A 4x4 matrix using column-major storage.
27 ///
28 /// Utility methods that need to make assumptions about normalized
29 /// device coordinates must use the following convention:
30 /// * Left-handed coordinate system. Positive rotation is
31 /// clockwise about axis of rotation.
32 /// * Lower left corner is -1.0f, -1.0.
33 /// * Upper right corner is 1.0f, 1.0.
34 /// * Visible z-space is from 0.0 to 1.0.
35 /// * This is NOT the same as OpenGL! Be careful.
36 /// * NDC origin is at (0.0f, 0.0f, 0.5f).
37 struct Matrix {
38 union {
39 Scalar m[16];
40 Scalar e[4][4];
41 Vector4 vec[4];
42 };
43
44 //----------------------------------------------------------------------------
45 /// Constructs a default identity matrix.
46 ///
47 constexpr Matrix()
48 // clang-format off
49 : vec{ Vector4(1.0f, 0.0f, 0.0f, 0.0f),
50 Vector4(0.0f, 1.0f, 0.0f, 0.0f),
51 Vector4(0.0f, 0.0f, 1.0f, 0.0f),
52 Vector4(0.0f, 0.0f, 0.0f, 1.0f)} {}
53 // clang-format on
54
55 // clang-format off
56 constexpr Matrix(Scalar m0, Scalar m1, Scalar m2, Scalar m3,
57 Scalar m4, Scalar m5, Scalar m6, Scalar m7,
58 Scalar m8, Scalar m9, Scalar m10, Scalar m11,
59 Scalar m12, Scalar m13, Scalar m14, Scalar m15)
60 : vec{Vector4(m0, m1, m2, m3),
61 Vector4(m4, m5, m6, m7),
62 Vector4(m8, m9, m10, m11),
63 Vector4(m12, m13, m14, m15)} {}
64 // clang-format on
65
66 explicit Matrix(const MatrixDecomposition& decomposition);
67
68 // clang-format off
69 static constexpr Matrix MakeColumn(
70 Scalar m0, Scalar m1, Scalar m2, Scalar m3,
71 Scalar m4, Scalar m5, Scalar m6, Scalar m7,
72 Scalar m8, Scalar m9, Scalar m10, Scalar m11,
73 Scalar m12, Scalar m13, Scalar m14, Scalar m15){
74 return Matrix(m0, m1, m2, m3,
75 m4, m5, m6, m7,
76 m8, m9, m10, m11,
77 m12, m13, m14, m15);
78
79 }
80 // clang-format on
81
82 // clang-format off
83 static constexpr Matrix MakeRow(
84 Scalar m0, Scalar m1, Scalar m2, Scalar m3,
85 Scalar m4, Scalar m5, Scalar m6, Scalar m7,
86 Scalar m8, Scalar m9, Scalar m10, Scalar m11,
87 Scalar m12, Scalar m13, Scalar m14, Scalar m15){
88 return Matrix(m0, m4, m8, m12,
89 m1, m5, m9, m13,
90 m2, m6, m10, m14,
91 m3, m7, m11, m15);
92 }
93 // clang-format on
94
95 static constexpr Matrix MakeTranslation(const Vector3& t) {
96 // clang-format off
97 return Matrix(1.0f, 0.0f, 0.0f, 0.0f,
98 0.0f, 1.0f, 0.0f, 0.0f,
99 0.0f, 0.0f, 1.0f, 0.0f,
100 t.x, t.y, t.z, 1.0f);
101 // clang-format on
102 }
103
104 static constexpr Matrix MakeScale(const Vector3& s) {
105 // clang-format off
106 return Matrix(s.x, 0.0f, 0.0f, 0.0f,
107 0.0f, s.y, 0.0f, 0.0f,
108 0.0f, 0.0f, s.z, 0.0f,
109 0.0f, 0.0f, 0.0f, 1.0f);
110 // clang-format on
111 }
112
113 static constexpr Matrix MakeTranslateScale(const Vector3& s,
114 const Vector3& t) {
115 // clang-format off
116 return Matrix(s.x, 0.0f, 0.0f, 0.0f,
117 0.0f, s.y, 0.0f, 0.0f,
118 0.0f, 0.0f, s.z, 0.0f,
119 t.x , t.y, t.z, 1.0f);
120 // clang-format on
121 }
122
123 static constexpr Matrix MakeScale(const Vector2& s) {
124 return MakeScale(Vector3(s.x, s.y, 1.0f));
125 }
126
127 static constexpr Matrix MakeSkew(Scalar sx, Scalar sy) {
128 // clang-format off
129 return Matrix(1.0f, sy , 0.0f, 0.0f,
130 sx , 1.0f, 0.0f, 0.0f,
131 0.0f, 0.0f, 1.0f, 0.0f,
132 0.0f, 0.0f, 0.0f, 1.0f);
133 // clang-format on
134 }
135
136 static Matrix MakeRotation(Quaternion q) {
137 // clang-format off
138 return Matrix(
139 1.0f - 2.0f * q.y * q.y - 2.0f * q.z * q.z,
140 2.0f * q.x * q.y + 2.0f * q.z * q.w,
141 2.0f * q.x * q.z - 2.0f * q.y * q.w,
142 0.0f,
143
144 2.0f * q.x * q.y - 2.0f * q.z * q.w,
145 1.0f - 2.0f * q.x * q.x - 2.0f * q.z * q.z,
146 2.0f * q.y * q.z + 2.0f * q.x * q.w,
147 0.0f,
148
149 2.0f * q.x * q.z + 2.0f * q.y * q.w,
150 2.0f * q.y * q.z - 2.0f * q.x * q.w,
151 1.0f - 2.0f * q.x * q.x - 2.0f * q.y * q.y,
152 0.0f,
153
154 0.0f,
155 0.0f,
156 0.0f,
157 1.0f);
158 // clang-format on
159 }
160
161 static Matrix MakeRotation(Radians radians, const Vector4& r) {
162 const Vector4 v = r.Normalize();
163
164 const Vector2 cos_sin = CosSin(radians);
165 const Scalar cosine = cos_sin.x;
166 const Scalar cosp = 1.0f - cosine;
167 const Scalar sine = cos_sin.y;
168
169 // clang-format off
170 return Matrix(
171 cosine + cosp * v.x * v.x,
172 cosp * v.x * v.y + v.z * sine,
173 cosp * v.x * v.z - v.y * sine,
174 0.0f,
175
176 cosp * v.x * v.y - v.z * sine,
177 cosine + cosp * v.y * v.y,
178 cosp * v.y * v.z + v.x * sine,
179 0.0f,
180
181 cosp * v.x * v.z + v.y * sine,
182 cosp * v.y * v.z - v.x * sine,
183 cosine + cosp * v.z * v.z,
184 0.0f,
185
186 0.0f,
187 0.0f,
188 0.0f,
189 1.0f);
190 // clang-format on
191 }
192
193 static Matrix MakeRotationX(Radians r) {
194 const Vector2 cos_sin = CosSin(r);
195 const Scalar cosine = cos_sin.x;
196 const Scalar sine = cos_sin.y;
197
198 // clang-format off
199 return Matrix(
200 1.0f, 0.0f, 0.0f, 0.0f,
201 0.0f, cosine, sine, 0.0f,
202 0.0f, -sine, cosine, 0.0f,
203 0.0f, 0.0f, 0.0f, 1.0f
204 );
205 // clang-format on
206 }
207
208 static Matrix MakeRotationY(Radians r) {
209 const Vector2 cos_sin = CosSin(r);
210 const Scalar cosine = cos_sin.x;
211 const Scalar sine = cos_sin.y;
212
213 // clang-format off
214 return Matrix(
215 cosine, 0.0f, -sine, 0.0f,
216 0.0f, 1.0f, 0.0f, 0.0f,
217 sine, 0.0f, cosine, 0.0f,
218 0.0f, 0.0f, 0.0f, 1.0f
219 );
220 // clang-format on
221 }
222
223 static Matrix MakeRotationZ(Radians r) {
224 const Vector2 cos_sin = CosSin(r);
225 const Scalar cosine = cos_sin.x;
226 const Scalar sine = cos_sin.y;
227
228 // clang-format off
229 return Matrix (
230 cosine, sine, 0.0f, 0.0f,
231 -sine, cosine, 0.0f, 0.0f,
232 0.0f, 0.0f, 1.0f, 0.0f,
233 0.0f, 0.0f, 0.0f, 1.0
234 );
235 // clang-format on
236 }
237
238 /// The Matrix without its `w` components (without translation).
239 constexpr Matrix Basis() const {
240 // clang-format off
241 return Matrix(
242 m[0], m[1], m[2], 0.0f,
243 m[4], m[5], m[6], 0.0f,
244 m[8], m[9], m[10], 0.0f,
245 0.0f, 0.0f, 0.0f, 1.0
246 );
247 // clang-format on
248 }
249
250 constexpr Matrix Translate(const Vector3& t) const {
251 // clang-format off
252 return Matrix(m[0], m[1], m[2], m[3],
253 m[4], m[5], m[6], m[7],
254 m[8], m[9], m[10], m[11],
255 m[0] * t.x + m[4] * t.y + m[8] * t.z + m[12],
256 m[1] * t.x + m[5] * t.y + m[9] * t.z + m[13],
257 m[2] * t.x + m[6] * t.y + m[10] * t.z + m[14],
258 m[3] * t.x + m[7] * t.y + m[11] * t.z + m[15]);
259 // clang-format on
260 }
261
262 constexpr Matrix Scale(const Vector3& s) const {
263 // clang-format off
264 return Matrix(m[0] * s.x, m[1] * s.x, m[2] * s.x, m[3] * s.x,
265 m[4] * s.y, m[5] * s.y, m[6] * s.y, m[7] * s.y,
266 m[8] * s.z, m[9] * s.z, m[10] * s.z, m[11] * s.z,
267 m[12] , m[13] , m[14] , m[15] );
268 // clang-format on
269 }
270
271 constexpr Matrix Multiply(const Matrix& o) const {
272 // clang-format off
273 return Matrix(
274 m[0] * o.m[0] + m[4] * o.m[1] + m[8] * o.m[2] + m[12] * o.m[3],
275 m[1] * o.m[0] + m[5] * o.m[1] + m[9] * o.m[2] + m[13] * o.m[3],
276 m[2] * o.m[0] + m[6] * o.m[1] + m[10] * o.m[2] + m[14] * o.m[3],
277 m[3] * o.m[0] + m[7] * o.m[1] + m[11] * o.m[2] + m[15] * o.m[3],
278 m[0] * o.m[4] + m[4] * o.m[5] + m[8] * o.m[6] + m[12] * o.m[7],
279 m[1] * o.m[4] + m[5] * o.m[5] + m[9] * o.m[6] + m[13] * o.m[7],
280 m[2] * o.m[4] + m[6] * o.m[5] + m[10] * o.m[6] + m[14] * o.m[7],
281 m[3] * o.m[4] + m[7] * o.m[5] + m[11] * o.m[6] + m[15] * o.m[7],
282 m[0] * o.m[8] + m[4] * o.m[9] + m[8] * o.m[10] + m[12] * o.m[11],
283 m[1] * o.m[8] + m[5] * o.m[9] + m[9] * o.m[10] + m[13] * o.m[11],
284 m[2] * o.m[8] + m[6] * o.m[9] + m[10] * o.m[10] + m[14] * o.m[11],
285 m[3] * o.m[8] + m[7] * o.m[9] + m[11] * o.m[10] + m[15] * o.m[11],
286 m[0] * o.m[12] + m[4] * o.m[13] + m[8] * o.m[14] + m[12] * o.m[15],
287 m[1] * o.m[12] + m[5] * o.m[13] + m[9] * o.m[14] + m[13] * o.m[15],
288 m[2] * o.m[12] + m[6] * o.m[13] + m[10] * o.m[14] + m[14] * o.m[15],
289 m[3] * o.m[12] + m[7] * o.m[13] + m[11] * o.m[14] + m[15] * o.m[15]);
290 // clang-format on
291 }
292
293 constexpr Matrix Transpose() const {
294 // clang-format off
295 return {
296 m[0], m[4], m[8], m[12],
297 m[1], m[5], m[9], m[13],
298 m[2], m[6], m[10], m[14],
299 m[3], m[7], m[11], m[15],
300 };
301 // clang-format on
302 }
303
304 Matrix Invert() const;
305
306 Scalar GetDeterminant() const;
307
308 bool IsInvertible() const { return GetDeterminant() != 0; }
309
310 constexpr Scalar GetMaxBasisLengthXY() const {
311 // The full basis computation requires computing the squared scaling factor
312 // for translate/scale only matrices. This substantially limits the range of
313 // precision for small and large scales. Instead, check for the common cases
314 // and directly return the max scaling factor.
315 if (e[0][1] == 0 && e[1][0] == 0) {
316 return std::max(std::abs(e[0][0]), std::abs(e[1][1]));
317 }
318 return std::sqrt(std::max(e[0][0] * e[0][0] + e[0][1] * e[0][1],
319 e[1][0] * e[1][0] + e[1][1] * e[1][1]));
320 }
321
322 constexpr Vector3 GetBasisX() const { return Vector3(m[0], m[1], m[2]); }
323
324 constexpr Vector3 GetBasisY() const { return Vector3(m[4], m[5], m[6]); }
325
326 constexpr Vector3 GetBasisZ() const { return Vector3(m[8], m[9], m[10]); }
327
328 constexpr Vector3 GetScale() const {
329 return Vector3(GetBasisX().GetLength(), GetBasisY().GetLength(),
330 GetBasisZ().GetLength());
331 }
332
333 constexpr Scalar GetDirectionScale(Vector3 direction) const {
334 return 1.0f / (this->Basis().Invert() * direction.Normalize()).GetLength() *
335 direction.GetLength();
336 }
337
338 constexpr bool IsFinite() const {
339 return vec[0].IsFinite() && vec[1].IsFinite() && vec[2].IsFinite() &&
340 vec[3].IsFinite();
341 }
342
343 constexpr bool IsAffine() const {
344 return (m[2] == 0 && m[3] == 0 && m[6] == 0 && m[7] == 0 && m[8] == 0 &&
345 m[9] == 0 && m[10] == 1 && m[11] == 0 && m[14] == 0 && m[15] == 1);
346 }
347
348 constexpr bool HasPerspective2D() const {
349 return m[3] != 0 || m[7] != 0 || m[15] != 1;
350 }
351
352 constexpr bool HasPerspective() const {
353 return m[3] != 0 || m[7] != 0 || m[11] != 0 || m[15] != 1;
354 }
355
356 constexpr bool HasTranslation() const { return m[12] != 0 || m[13] != 0; }
357
358 constexpr bool IsAligned2D(Scalar tolerance = 0) const {
359 if (HasPerspective2D()) {
360 return false;
361 }
362 if (ScalarNearlyZero(m[1], tolerance) &&
363 ScalarNearlyZero(m[4], tolerance)) {
364 return true;
365 }
366 if (ScalarNearlyZero(m[0], tolerance) &&
367 ScalarNearlyZero(m[5], tolerance)) {
368 return true;
369 }
370 return false;
371 }
372
373 constexpr bool IsAligned(Scalar tolerance = 0) const {
374 if (HasPerspective()) {
375 return false;
376 }
377 int v[] = {!ScalarNearlyZero(m[0], tolerance), //
378 !ScalarNearlyZero(m[1], tolerance), //
379 !ScalarNearlyZero(m[2], tolerance), //
380 !ScalarNearlyZero(m[4], tolerance), //
381 !ScalarNearlyZero(m[5], tolerance), //
382 !ScalarNearlyZero(m[6], tolerance), //
383 !ScalarNearlyZero(m[8], tolerance), //
384 !ScalarNearlyZero(m[9], tolerance), //
385 !ScalarNearlyZero(m[10], tolerance)};
386 // Check if all three basis vectors are aligned to an axis.
387 if (v[0] + v[1] + v[2] != 1 || //
388 v[3] + v[4] + v[5] != 1 || //
389 v[6] + v[7] + v[8] != 1) {
390 return false;
391 }
392 // Ensure that none of the basis vectors overlap.
393 if (v[0] + v[3] + v[6] != 1 || //
394 v[1] + v[4] + v[7] != 1 || //
395 v[2] + v[5] + v[8] != 1) {
396 return false;
397 }
398 return true;
399 }
400
401 constexpr bool IsIdentity() const {
402 return (
403 // clang-format off
404 m[0] == 1.0f && m[1] == 0.0f && m[2] == 0.0f && m[3] == 0.0f &&
405 m[4] == 0.0f && m[5] == 1.0f && m[6] == 0.0f && m[7] == 0.0f &&
406 m[8] == 0.0f && m[9] == 0.0f && m[10] == 1.0f && m[11] == 0.0f &&
407 m[12] == 0.0f && m[13] == 0.0f && m[14] == 0.0f && m[15] == 1.0f
408 // clang-format on
409 );
410 }
411
412 /// @brief Returns true if the matrix has no entries other than translation
413 /// components. Note that an identity matrix meets this criteria.
414 constexpr bool IsTranslationOnly() const {
415 return (
416 // clang-format off
417 m[0] == 1.0 && m[1] == 0.0 && m[2] == 0.0 && m[3] == 0.0 &&
418 m[4] == 0.0 && m[5] == 1.0 && m[6] == 0.0 && m[7] == 0.0 &&
419 m[8] == 0.0 && m[9] == 0.0 && m[10] == 1.0 && m[11] == 0.0 &&
420 m[15] == 1.0
421 // clang-format on
422 );
423 }
424
425 /// @brief Returns true if the matrix has a scale-only basis and is
426 /// non-projective. Note that an identity matrix meets this criteria.
427 constexpr bool IsTranslationScaleOnly() const {
428 return (
429 // clang-format off
430 m[0] != 0.0 && m[1] == 0.0 && m[2] == 0.0 && m[3] == 0.0 &&
431 m[4] == 0.0 && m[5] != 0.0 && m[6] == 0.0 && m[7] == 0.0 &&
432 m[8] == 0.0 && m[9] == 0.0 && m[10] != 0.0 && m[11] == 0.0 &&
433 m[15] == 1.0
434 // clang-format on
435 );
436 }
437
438 std::optional<MatrixDecomposition> Decompose() const;
439
440 bool Equals(const Matrix& matrix, Scalar epsilon = 1e-5f) const {
441 const Scalar* a = m;
442 const Scalar* b = matrix.m;
443 return ScalarNearlyEqual(a[0], b[0], epsilon) &&
444 ScalarNearlyEqual(a[1], b[1], epsilon) &&
445 ScalarNearlyEqual(a[2], b[2], epsilon) &&
446 ScalarNearlyEqual(a[3], b[3], epsilon) &&
447 ScalarNearlyEqual(a[4], b[4], epsilon) &&
448 ScalarNearlyEqual(a[5], b[5], epsilon) &&
449 ScalarNearlyEqual(a[6], b[6], epsilon) &&
450 ScalarNearlyEqual(a[7], b[7], epsilon) &&
451 ScalarNearlyEqual(a[8], b[8], epsilon) &&
452 ScalarNearlyEqual(a[9], b[9], epsilon) &&
453 ScalarNearlyEqual(a[10], b[10], epsilon) &&
454 ScalarNearlyEqual(a[11], b[11], epsilon) &&
455 ScalarNearlyEqual(a[12], b[12], epsilon) &&
456 ScalarNearlyEqual(a[13], b[13], epsilon) &&
457 ScalarNearlyEqual(a[14], b[14], epsilon) &&
458 ScalarNearlyEqual(a[15], b[15], epsilon);
459 }
460
461 constexpr bool operator==(const Matrix& m) const {
462 // clang-format off
463 return vec[0] == m.vec[0]
464 && vec[1] == m.vec[1]
465 && vec[2] == m.vec[2]
466 && vec[3] == m.vec[3];
467 // clang-format on
468 }
469
470 constexpr bool operator!=(const Matrix& m) const {
471 // clang-format off
472 return vec[0] != m.vec[0]
473 || vec[1] != m.vec[1]
474 || vec[2] != m.vec[2]
475 || vec[3] != m.vec[3];
476 // clang-format on
477 }
478
479 Matrix operator+(const Vector3& t) const { return Translate(t); }
480
481 Matrix operator-(const Vector3& t) const { return Translate(-t); }
482
483 Matrix operator*(const Matrix& m) const { return Multiply(m); }
484
485 Matrix operator+(const Matrix& m) const;
486
487 constexpr Vector4 operator*(const Vector4& v) const {
488 return Vector4(v.x * m[0] + v.y * m[4] + v.z * m[8] + v.w * m[12],
489 v.x * m[1] + v.y * m[5] + v.z * m[9] + v.w * m[13],
490 v.x * m[2] + v.y * m[6] + v.z * m[10] + v.w * m[14],
491 v.x * m[3] + v.y * m[7] + v.z * m[11] + v.w * m[15]);
492 }
493
494 constexpr Vector3 operator*(const Vector3& v) const {
495 Scalar w = v.x * m[3] + v.y * m[7] + v.z * m[11] + m[15];
496 Vector3 result(v.x * m[0] + v.y * m[4] + v.z * m[8] + m[12],
497 v.x * m[1] + v.y * m[5] + v.z * m[9] + m[13],
498 v.x * m[2] + v.y * m[6] + v.z * m[10] + m[14]);
499
500 // This is Skia's behavior, but it may be reasonable to allow UB for the w=0
501 // case.
502 if (w) {
503 w = 1 / w;
504 }
505 return result * w;
506 }
507
508 constexpr Point operator*(const Point& v) const {
509 Scalar w = v.x * m[3] + v.y * m[7] + m[15];
510 Point result(v.x * m[0] + v.y * m[4] + m[12],
511 v.x * m[1] + v.y * m[5] + m[13]);
512
513 // This is Skia's behavior, but it may be reasonable to allow UB for the w=0
514 // case.
515 if (w) {
516 w = 1 / w;
517 }
518 return result * w;
519 }
520
521 constexpr Vector3 TransformHomogenous(const Point& v) const {
522 return Vector3(v.x * m[0] + v.y * m[4] + m[12],
523 v.x * m[1] + v.y * m[5] + m[13],
524 v.x * m[3] + v.y * m[7] + m[15]);
525 }
526
527 constexpr Vector4 TransformDirection(const Vector4& v) const {
528 return Vector4(v.x * m[0] + v.y * m[4] + v.z * m[8],
529 v.x * m[1] + v.y * m[5] + v.z * m[9],
530 v.x * m[2] + v.y * m[6] + v.z * m[10], v.w);
531 }
532
533 constexpr Vector3 TransformDirection(const Vector3& v) const {
534 return Vector3(v.x * m[0] + v.y * m[4] + v.z * m[8],
535 v.x * m[1] + v.y * m[5] + v.z * m[9],
536 v.x * m[2] + v.y * m[6] + v.z * m[10]);
537 }
538
539 constexpr Vector2 TransformDirection(const Vector2& v) const {
540 return Vector2(v.x * m[0] + v.y * m[4], v.x * m[1] + v.y * m[5]);
541 }
542
543 constexpr Quad Transform(const Quad& quad) const {
544 return {
545 *this * quad[0],
546 *this * quad[1],
547 *this * quad[2],
548 *this * quad[3],
549 };
550 }
551
552 template <class T>
553 static constexpr Matrix MakeOrthographic(TSize<T> size) {
554 // Per assumptions about NDC documented above.
555 const auto scale =
556 MakeScale({2.0f / static_cast<Scalar>(size.width),
557 -2.0f / static_cast<Scalar>(size.height), 0.0f});
558 const auto translate = MakeTranslation({-1.0f, 1.0f, 0.5f});
559 return translate * scale;
560 }
561
562 static constexpr Matrix MakePerspective(Radians fov_y,
563 Scalar aspect_ratio,
564 Scalar z_near,
565 Scalar z_far) {
566 Scalar height = std::tan(fov_y.radians * 0.5f);
567 Scalar width = height * aspect_ratio;
568
569 // clang-format off
570 return {
571 1.0f / width, 0.0f, 0.0f, 0.0f,
572 0.0f, 1.0f / height, 0.0f, 0.0f,
573 0.0f, 0.0f, z_far / (z_far - z_near), 1.0f,
574 0.0f, 0.0f, -(z_far * z_near) / (z_far - z_near), 0.0f,
575 };
576 // clang-format on
577 }
578
579 template <class T>
580 static constexpr Matrix MakePerspective(Radians fov_y,
581 TSize<T> size,
582 Scalar z_near,
583 Scalar z_far) {
584 return MakePerspective(fov_y, static_cast<Scalar>(size.width) / size.height,
585 z_near, z_far);
586 }
587
588 static constexpr Matrix MakeLookAt(Vector3 position,
589 Vector3 target,
590 Vector3 up) {
591 Vector3 forward = (target - position).Normalize();
592 Vector3 right = up.Cross(forward);
593 up = forward.Cross(right);
594
595 // clang-format off
596 return {
597 right.x, up.x, forward.x, 0.0f,
598 right.y, up.y, forward.y, 0.0f,
599 right.z, up.z, forward.z, 0.0f,
600 -right.Dot(position), -up.Dot(position), -forward.Dot(position), 1.0f
601 };
602 // clang-format on
603 }
604
605 static constexpr Vector2 CosSin(Radians radians) {
606 // The precision of a float around 1.0 is much lower than it is
607 // around 0.0, so we end up with cases on quadrant rotations where
608 // we get a +/-1.0 for one of the values and a non-zero value for
609 // the other. This happens around quadrant rotations which makes it
610 // especially common and results in unclean quadrant rotation
611 // matrices which do not return true from |IsAligned[2D]| even
612 // though that is exactly where you need them to exhibit that property.
613 // It also injects small floating point mantissa errors into the
614 // matrices whenever you concatenate them with a quadrant rotation.
615 //
616 // This issue is also exacerbated by the fact that, in radians, the
617 // angles for quadrant rotations are irrational numbers. The measuring
618 // error for representing 90 degree multiples is small enough that
619 // either sin or cos will return a value near +/-1.0, but not small
620 // enough that the other value will be a clean 0.0.
621 //
622 // Some geometry packages simply discard very small numbers from
623 // sin/cos, but the following approach specifically targets just the
624 // area around a quadrant rotation (where either the sin or cos are
625 // measuring as +/-1.0) for symmetry of precision.
626
627 Scalar sin = std::sin(radians.radians);
628 if (std::abs(sin) == 1.0f) {
629 // 90 or 270 degrees (mod 360)
630 return {0.0f, sin};
631 } else {
632 Scalar cos = std::cos(radians.radians);
633 if (std::abs(cos) == 1.0f) {
634 // 0 or 180 degrees (mod 360)
635 return {cos, 0.0f};
636 }
637 return {cos, sin};
638 }
639 }
640 };
641
642 static_assert(sizeof(struct Matrix) == sizeof(Scalar) * 16,
643 "The matrix must be of consistent size.");
644
645 } // namespace impeller
646
647 namespace std {
648 inline std::ostream& operator<<(std::ostream& out, const impeller::Matrix& m) {
649 out << "(" << std::endl << std::fixed;
650 for (size_t i = 0; i < 4u; i++) {
651 for (size_t j = 0; j < 4u; j++) {
652 out << std::setw(15) << m.e[j][i] << ",";
653 }
654 out << std::endl;
655 }
656 out << ")";
657 return out;
658 }
659
660 } // namespace std
661
662 #endif // FLUTTER_IMPELLER_GEOMETRY_MATRIX_H_
impeller::Matrix::MakeSkew
static constexpr Matrix MakeSkew(Scalar sx, Scalar sy)
Definition: matrix.h:127
impeller::Matrix::HasPerspective
constexpr bool HasPerspective() const
Definition: matrix.h:352
impeller::Matrix::operator+
Matrix operator+(const Vector3 &t) const
Definition: matrix.h:479
impeller::Matrix::m
Scalar m[16]
Definition: matrix.h:39
impeller::Vector3::Dot
constexpr Scalar Dot(const Vector3 &other) const
Definition: vector.h:54
impeller::Matrix::TransformHomogenous
constexpr Vector3 TransformHomogenous(const Point &v) const
Definition: matrix.h:521
impeller::Matrix::Decompose
std::optional< MatrixDecomposition > Decompose() const
Definition: matrix.cc:200
impeller::Matrix::Equals
bool Equals(const Matrix &matrix, Scalar epsilon=1e-5f) const
Definition: matrix.h:440
impeller::Matrix::MakeRotationX
static Matrix MakeRotationX(Radians r)
Definition: matrix.h:193
impeller::Matrix::Matrix
constexpr Matrix()
Definition: matrix.h:47
impeller::Quaternion::z
Scalar z
Definition: quaternion.h:19
point.h
impeller::TPoint::y
Type y
Definition: point.h:31
impeller::Scalar
float Scalar
Definition: scalar.h:18
impeller::Vector3::Cross
constexpr Vector3 Cross(const Vector3 &other) const
Definition: vector.h:62
impeller::Matrix::MakePerspective
static constexpr Matrix MakePerspective(Radians fov_y, TSize< T > size, Scalar z_near, Scalar z_far)
Definition: matrix.h:580
impeller::Matrix::MakeTranslateScale
static constexpr Matrix MakeTranslateScale(const Vector3 &s, const Vector3 &t)
Definition: matrix.h:113
impeller::Vector4::Normalize
Vector4 Normalize() const
Definition: vector.h:263
impeller::Quaternion::w
Scalar w
Definition: quaternion.h:20
impeller::Matrix::operator-
Matrix operator-(const Vector3 &t) const
Definition: matrix.h:481
impeller::Matrix::IsInvertible
bool IsInvertible() const
Definition: matrix.h:308
impeller::Matrix::operator*
constexpr Point operator*(const Point &v) const
Definition: matrix.h:508
impeller::Vector4
Definition: vector.h:232
impeller::Matrix::MakeRotation
static Matrix MakeRotation(Quaternion q)
Definition: matrix.h:136
impeller::Matrix::IsTranslationOnly
constexpr bool IsTranslationOnly() const
Returns true if the matrix has no entries other than translation components. Note that an identity ma...
Definition: matrix.h:414
impeller::Matrix::IsFinite
constexpr bool IsFinite() const
Definition: matrix.h:338
impeller::Vector2
Point Vector2
Definition: point.h:331
impeller::Matrix::MakeRotationY
static Matrix MakeRotationY(Radians r)
Definition: matrix.h:208
impeller::Matrix::GetDeterminant
Scalar GetDeterminant() const
Definition: matrix.cc:162
quaternion.h
std::operator<<
std::ostream & operator<<(std::ostream &out, const impeller::Color &c)
Definition: color.h:926
impeller::Matrix::operator*
Matrix operator*(const Matrix &m) const
Definition: matrix.h:483
impeller::Radians::radians
Scalar radians
Definition: scalar.h:44
impeller::Matrix::MakeRow
static constexpr Matrix MakeRow(Scalar m0, Scalar m1, Scalar m2, Scalar m3, Scalar m4, Scalar m5, Scalar m6, Scalar m7, Scalar m8, Scalar m9, Scalar m10, Scalar m11, Scalar m12, Scalar m13, Scalar m14, Scalar m15)
Definition: matrix.h:83
impeller::Matrix::MakeTranslation
static constexpr Matrix MakeTranslation(const Vector3 &t)
Definition: matrix.h:95
impeller::Vector3::x
Scalar x
Definition: vector.h:23
impeller::Matrix::MakeRotation
static Matrix MakeRotation(Radians radians, const Vector4 &r)
Definition: matrix.h:161
impeller::Quaternion::x
Scalar x
Definition: quaternion.h:17
impeller::Matrix::e
Scalar e[4][4]
Definition: matrix.h:40
impeller::Matrix::vec
Vector4 vec[4]
Definition: matrix.h:41
impeller::Matrix::MakeLookAt
static constexpr Matrix MakeLookAt(Vector3 position, Vector3 target, Vector3 up)
Definition: matrix.h:588
impeller::Matrix::MakePerspective
static constexpr Matrix MakePerspective(Radians fov_y, Scalar aspect_ratio, Scalar z_near, Scalar z_far)
Definition: matrix.h:562
impeller::Matrix::Basis
constexpr Matrix Basis() const
The Matrix without its w components (without translation).
Definition: matrix.h:239
impeller::TSize
Definition: size.h:25
impeller::Matrix::TransformDirection
constexpr Vector3 TransformDirection(const Vector3 &v) const
Definition: matrix.h:533
impeller::Quaternion
Definition: quaternion.h:14
impeller::Quad
std::array< Point, 4 > Quad
Definition: point.h:332
impeller::Matrix::CosSin
static constexpr Vector2 CosSin(Radians radians)
Definition: matrix.h:605
impeller::Matrix::Multiply
constexpr Matrix Multiply(const Matrix &o) const
Definition: matrix.h:271
impeller::Matrix::GetScale
constexpr Vector3 GetScale() const
Definition: matrix.h:328
impeller::Matrix::operator==
constexpr bool operator==(const Matrix &m) const
Definition: matrix.h:461
impeller::Matrix::Transpose
constexpr Matrix Transpose() const
Definition: matrix.h:293
impeller::Matrix::operator*
constexpr Vector4 operator*(const Vector4 &v) const
Definition: matrix.h:487
impeller::Matrix::IsTranslationScaleOnly
constexpr bool IsTranslationScaleOnly() const
Returns true if the matrix has a scale-only basis and is non-projective. Note that an identity matrix...
Definition: matrix.h:427
impeller::Matrix::Translate
constexpr Matrix Translate(const Vector3 &t) const
Definition: matrix.h:250
impeller::Matrix::Matrix
constexpr Matrix(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:56
impeller::Matrix::MakeColumn
static constexpr Matrix MakeColumn(Scalar m0, Scalar m1, Scalar m2, Scalar m3, Scalar m4, Scalar m5, Scalar m6, Scalar m7, Scalar m8, Scalar m9, Scalar m10, Scalar m11, Scalar m12, Scalar m13, Scalar m14, Scalar m15)
Definition: matrix.h:69
impeller::Matrix::TransformDirection
constexpr Vector2 TransformDirection(const Vector2 &v) const
Definition: matrix.h:539
impeller::Vector3::z
Scalar z
Definition: vector.h:25
impeller::Matrix::IsAffine
constexpr bool IsAffine() const
Definition: matrix.h:343
impeller::Radians
Definition: scalar.h:43
impeller::ScalarNearlyZero
constexpr bool ScalarNearlyZero(Scalar x, Scalar tolerance=kEhCloseEnough)
Definition: scalar.h:30
impeller::Vector4::x
Scalar x
Definition: vector.h:235
impeller::Vector3::y
Scalar y
Definition: vector.h:24
impeller::Vector3::GetLength
constexpr Scalar GetLength() const
Definition: vector.h:47
impeller::Matrix::GetBasisZ
constexpr Vector3 GetBasisZ() const
Definition: matrix.h:326
impeller::TSize::width
Type width
Definition: size.h:28
impeller::Matrix::Transform
constexpr Quad Transform(const Quad &quad) const
Definition: matrix.h:543
impeller::Matrix::Invert
Matrix Invert() const
Definition: matrix.cc:97
impeller::TPoint::x
Type x
Definition: point.h:30
impeller::Matrix::HasTranslation
constexpr bool HasTranslation() const
Definition: matrix.h:356
impeller::Matrix::IsIdentity
constexpr bool IsIdentity() const
Definition: matrix.h:401
impeller::Matrix::GetDirectionScale
constexpr Scalar GetDirectionScale(Vector3 direction) const
Definition: matrix.h:333
scalar.h
impeller::Vector3::Normalize
constexpr Vector3 Normalize() const
Definition: vector.h:49
impeller::Matrix::TransformDirection
constexpr Vector4 TransformDirection(const Vector4 &v) const
Definition: matrix.h:527
impeller::Vector4::w
Scalar w
Definition: vector.h:238
impeller::Matrix::MakeRotationZ
static Matrix MakeRotationZ(Radians r)
Definition: matrix.h:223
vector.h
impeller::Matrix::GetMaxBasisLengthXY
constexpr Scalar GetMaxBasisLengthXY() const
Definition: matrix.h:310
std
Definition: comparable.h:95
impeller::Vector4::y
Scalar y
Definition: vector.h:236
shear.h
impeller::TPoint< Scalar >
impeller::saturated::b
SI b
Definition: saturated_math.h:87
impeller::Matrix::operator*
constexpr Vector3 operator*(const Vector3 &v) const
Definition: matrix.h:494
impeller::Matrix::operator!=
constexpr bool operator!=(const Matrix &m) const
Definition: matrix.h:470
impeller::Quaternion::y
Scalar y
Definition: quaternion.h:18
scale
const Scalar scale
Definition: stroke_path_geometry.cc:316
impeller::ScalarNearlyEqual
constexpr bool ScalarNearlyEqual(Scalar x, Scalar y, Scalar tolerance=kEhCloseEnough)
Definition: scalar.h:35
impeller::Matrix::MakeOrthographic
static constexpr Matrix MakeOrthographic(TSize< T > size)
Definition: matrix.h:553
matrix_decomposition.h
impeller::TSize::height
Type height
Definition: size.h:29
impeller::Vector4::IsFinite
constexpr bool IsFinite() const
Definition: vector.h:258
impeller::Matrix::GetBasisY
constexpr Vector3 GetBasisY() const
Definition: matrix.h:324
impeller::Vector4::z
Scalar z
Definition: vector.h:237
impeller
Definition: allocation.cc:12
impeller::Matrix::MakeScale
static constexpr Matrix MakeScale(const Vector3 &s)
Definition: matrix.h:104
impeller::Matrix::IsAligned2D
constexpr bool IsAligned2D(Scalar tolerance=0) const
Definition: matrix.h:358
impeller::Matrix::MakeScale
static constexpr Matrix MakeScale(const Vector2 &s)
Definition: matrix.h:123
impeller::Matrix::GetBasisX
constexpr Vector3 GetBasisX() const
Definition: matrix.h:322
impeller::Matrix::HasPerspective2D
constexpr bool HasPerspective2D() const
Definition: matrix.h:348
impeller::Matrix
A 4x4 matrix using column-major storage.
Definition: matrix.h:37
impeller::Vector3
Definition: vector.h:20
size.h
impeller::Matrix::Scale
constexpr Matrix Scale(const Vector3 &s) const
Definition: matrix.h:262
impeller::Matrix::IsAligned
constexpr bool IsAligned(Scalar tolerance=0) const
Definition: matrix.h:373