xref: /aosp_15_r20/external/skia/include/core/SkM44.h (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1 /*
2  * Copyright 2020 Google Inc.
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #ifndef SkM44_DEFINED
9 #define SkM44_DEFINED
10 
11 #include "include/core/SkMatrix.h"
12 #include "include/core/SkScalar.h"
13 #include "include/core/SkTypes.h"
14 
15 #include <cstring>
16 
17 struct SkRect;
18 
19 struct SK_API SkV2 {
20     float x, y;
21 
22     bool operator==(const SkV2 v) const { return x == v.x && y == v.y; }
23     bool operator!=(const SkV2 v) const { return !(*this == v); }
24 
DotSkV225     static SkScalar   Dot(SkV2 a, SkV2 b) { return a.x * b.x + a.y * b.y; }
CrossSkV226     static SkScalar Cross(SkV2 a, SkV2 b) { return a.x * b.y - a.y * b.x; }
NormalizeSkV227     static SkV2 Normalize(SkV2 v) { return v * (1.0f / v.length()); }
28 
29     SkV2 operator-() const { return {-x, -y}; }
30     SkV2 operator+(SkV2 v) const { return {x+v.x, y+v.y}; }
31     SkV2 operator-(SkV2 v) const { return {x-v.x, y-v.y}; }
32 
33     SkV2 operator*(SkV2 v) const { return {x*v.x, y*v.y}; }
34     friend SkV2 operator*(SkV2 v, SkScalar s) { return {v.x*s, v.y*s}; }
35     friend SkV2 operator*(SkScalar s, SkV2 v) { return {v.x*s, v.y*s}; }
36     friend SkV2 operator/(SkV2 v, SkScalar s) { return {v.x/s, v.y/s}; }
37     friend SkV2 operator/(SkScalar s, SkV2 v) { return {s/v.x, s/v.y}; }
38 
39     void operator+=(SkV2 v) { *this = *this + v; }
40     void operator-=(SkV2 v) { *this = *this - v; }
41     void operator*=(SkV2 v) { *this = *this * v; }
42     void operator*=(SkScalar s) { *this = *this * s; }
43     void operator/=(SkScalar s) { *this = *this / s; }
44 
lengthSquaredSkV245     SkScalar lengthSquared() const { return Dot(*this, *this); }
lengthSkV246     SkScalar length() const { return SkScalarSqrt(this->lengthSquared()); }
47 
dotSkV248     SkScalar   dot(SkV2 v) const { return Dot(*this, v); }
crossSkV249     SkScalar cross(SkV2 v) const { return Cross(*this, v); }
normalizeSkV250     SkV2 normalize()       const { return Normalize(*this); }
51 
ptrSkV252     const float* ptr() const { return &x; }
ptrSkV253     float* ptr() { return &x; }
54 };
55 
56 struct SK_API SkV3 {
57     float x, y, z;
58 
59     bool operator==(const SkV3& v) const {
60         return x == v.x && y == v.y && z == v.z;
61     }
62     bool operator!=(const SkV3& v) const { return !(*this == v); }
63 
DotSkV364     static SkScalar Dot(const SkV3& a, const SkV3& b) { return a.x*b.x + a.y*b.y + a.z*b.z; }
CrossSkV365     static SkV3   Cross(const SkV3& a, const SkV3& b) {
66         return { a.y*b.z - a.z*b.y, a.z*b.x - a.x*b.z, a.x*b.y - a.y*b.x };
67     }
NormalizeSkV368     static SkV3 Normalize(const SkV3& v) { return v * (1.0f / v.length()); }
69 
70     SkV3 operator-() const { return {-x, -y, -z}; }
71     SkV3 operator+(const SkV3& v) const { return { x + v.x, y + v.y, z + v.z }; }
72     SkV3 operator-(const SkV3& v) const { return { x - v.x, y - v.y, z - v.z }; }
73 
74     SkV3 operator*(const SkV3& v) const {
75         return { x*v.x, y*v.y, z*v.z };
76     }
77     friend SkV3 operator*(const SkV3& v, SkScalar s) {
78         return { v.x*s, v.y*s, v.z*s };
79     }
80     friend SkV3 operator*(SkScalar s, const SkV3& v) { return v*s; }
81 
82     void operator+=(SkV3 v) { *this = *this + v; }
83     void operator-=(SkV3 v) { *this = *this - v; }
84     void operator*=(SkV3 v) { *this = *this * v; }
85     void operator*=(SkScalar s) { *this = *this * s; }
86 
lengthSquaredSkV387     SkScalar lengthSquared() const { return Dot(*this, *this); }
lengthSkV388     SkScalar length() const { return SkScalarSqrt(Dot(*this, *this)); }
89 
dotSkV390     SkScalar dot(const SkV3& v) const { return Dot(*this, v); }
crossSkV391     SkV3   cross(const SkV3& v) const { return Cross(*this, v); }
normalizeSkV392     SkV3 normalize()            const { return Normalize(*this); }
93 
ptrSkV394     const float* ptr() const { return &x; }
ptrSkV395     float* ptr() { return &x; }
96 };
97 
98 struct SK_API SkV4 {
99     float x, y, z, w;
100 
101     bool operator==(const SkV4& v) const {
102         return x == v.x && y == v.y && z == v.z && w == v.w;
103     }
104     bool operator!=(const SkV4& v) const { return !(*this == v); }
105 
DotSkV4106     static SkScalar Dot(const SkV4& a, const SkV4& b) {
107         return a.x*b.x + a.y*b.y + a.z*b.z + a.w*b.w;
108     }
NormalizeSkV4109     static SkV4 Normalize(const SkV4& v) { return v * (1.0f / v.length()); }
110 
111     SkV4 operator-() const { return {-x, -y, -z, -w}; }
112     SkV4 operator+(const SkV4& v) const { return { x + v.x, y + v.y, z + v.z, w + v.w }; }
113     SkV4 operator-(const SkV4& v) const { return { x - v.x, y - v.y, z - v.z, w - v.w }; }
114 
115     SkV4 operator*(const SkV4& v) const {
116         return { x*v.x, y*v.y, z*v.z, w*v.w };
117     }
118     friend SkV4 operator*(const SkV4& v, SkScalar s) {
119         return { v.x*s, v.y*s, v.z*s, v.w*s };
120     }
121     friend SkV4 operator*(SkScalar s, const SkV4& v) { return v*s; }
122 
lengthSquaredSkV4123     SkScalar lengthSquared() const { return Dot(*this, *this); }
lengthSkV4124     SkScalar length() const { return SkScalarSqrt(Dot(*this, *this)); }
125 
dotSkV4126     SkScalar dot(const SkV4& v) const { return Dot(*this, v); }
normalizeSkV4127     SkV4 normalize()            const { return Normalize(*this); }
128 
ptrSkV4129     const float* ptr() const { return &x; }
ptrSkV4130     float* ptr() { return &x; }
131 
132     float operator[](int i) const {
133         SkASSERT(i >= 0 && i < 4);
134         return this->ptr()[i];
135     }
136     float& operator[](int i) {
137         SkASSERT(i >= 0 && i < 4);
138         return this->ptr()[i];
139     }
140 };
141 
142 /**
143  *  4x4 matrix used by SkCanvas and other parts of Skia.
144  *
145  *  Skia assumes a right-handed coordinate system:
146  *      +X goes to the right
147  *      +Y goes down
148  *      +Z goes into the screen (away from the viewer)
149  */
150 class SK_API SkM44 {
151 public:
152     SkM44(const SkM44& src) = default;
153     SkM44& operator=(const SkM44& src) = default;
154 
SkM44()155     constexpr SkM44()
156         : fMat{1, 0, 0, 0,
157                0, 1, 0, 0,
158                0, 0, 1, 0,
159                0, 0, 0, 1}
160         {}
161 
SkM44(const SkM44 & a,const SkM44 & b)162     SkM44(const SkM44& a, const SkM44& b) {
163         this->setConcat(a, b);
164     }
165 
166     enum Uninitialized_Constructor {
167         kUninitialized_Constructor
168     };
SkM44(Uninitialized_Constructor)169     SkM44(Uninitialized_Constructor) {}
170 
171     enum NaN_Constructor {
172         kNaN_Constructor
173     };
SkM44(NaN_Constructor)174     constexpr SkM44(NaN_Constructor)
175         : fMat{SK_ScalarNaN, SK_ScalarNaN, SK_ScalarNaN, SK_ScalarNaN,
176                SK_ScalarNaN, SK_ScalarNaN, SK_ScalarNaN, SK_ScalarNaN,
177                SK_ScalarNaN, SK_ScalarNaN, SK_ScalarNaN, SK_ScalarNaN,
178                SK_ScalarNaN, SK_ScalarNaN, SK_ScalarNaN, SK_ScalarNaN}
179     {}
180 
181     /**
182      *  The constructor parameters are in row-major order.
183      */
SkM44(SkScalar m0,SkScalar m4,SkScalar m8,SkScalar m12,SkScalar m1,SkScalar m5,SkScalar m9,SkScalar m13,SkScalar m2,SkScalar m6,SkScalar m10,SkScalar m14,SkScalar m3,SkScalar m7,SkScalar m11,SkScalar m15)184     constexpr SkM44(SkScalar m0, SkScalar m4, SkScalar m8,  SkScalar m12,
185                     SkScalar m1, SkScalar m5, SkScalar m9,  SkScalar m13,
186                     SkScalar m2, SkScalar m6, SkScalar m10, SkScalar m14,
187                     SkScalar m3, SkScalar m7, SkScalar m11, SkScalar m15)
188         // fMat is column-major order in memory.
189         : fMat{m0,  m1,  m2,  m3,
190                m4,  m5,  m6,  m7,
191                m8,  m9,  m10, m11,
192                m12, m13, m14, m15}
193     {}
194 
Rows(const SkV4 & r0,const SkV4 & r1,const SkV4 & r2,const SkV4 & r3)195     static SkM44 Rows(const SkV4& r0, const SkV4& r1, const SkV4& r2, const SkV4& r3) {
196         SkM44 m(kUninitialized_Constructor);
197         m.setRow(0, r0);
198         m.setRow(1, r1);
199         m.setRow(2, r2);
200         m.setRow(3, r3);
201         return m;
202     }
Cols(const SkV4 & c0,const SkV4 & c1,const SkV4 & c2,const SkV4 & c3)203     static SkM44 Cols(const SkV4& c0, const SkV4& c1, const SkV4& c2, const SkV4& c3) {
204         SkM44 m(kUninitialized_Constructor);
205         m.setCol(0, c0);
206         m.setCol(1, c1);
207         m.setCol(2, c2);
208         m.setCol(3, c3);
209         return m;
210     }
211 
RowMajor(const SkScalar r[16])212     static SkM44 RowMajor(const SkScalar r[16]) {
213         return SkM44(r[ 0], r[ 1], r[ 2], r[ 3],
214                      r[ 4], r[ 5], r[ 6], r[ 7],
215                      r[ 8], r[ 9], r[10], r[11],
216                      r[12], r[13], r[14], r[15]);
217     }
ColMajor(const SkScalar c[16])218     static SkM44 ColMajor(const SkScalar c[16]) {
219         return SkM44(c[0], c[4], c[ 8], c[12],
220                      c[1], c[5], c[ 9], c[13],
221                      c[2], c[6], c[10], c[14],
222                      c[3], c[7], c[11], c[15]);
223     }
224 
225     static SkM44 Translate(SkScalar x, SkScalar y, SkScalar z = 0) {
226         return SkM44(1, 0, 0, x,
227                      0, 1, 0, y,
228                      0, 0, 1, z,
229                      0, 0, 0, 1);
230     }
231 
232     static SkM44 Scale(SkScalar x, SkScalar y, SkScalar z = 1) {
233         return SkM44(x, 0, 0, 0,
234                      0, y, 0, 0,
235                      0, 0, z, 0,
236                      0, 0, 0, 1);
237     }
238 
Rotate(SkV3 axis,SkScalar radians)239     static SkM44 Rotate(SkV3 axis, SkScalar radians) {
240         SkM44 m(kUninitialized_Constructor);
241         m.setRotate(axis, radians);
242         return m;
243     }
244 
245     // Scales and translates 'src' to fill 'dst' exactly.
246     static SkM44 RectToRect(const SkRect& src, const SkRect& dst);
247 
248     static SkM44 LookAt(const SkV3& eye, const SkV3& center, const SkV3& up);
249     static SkM44 Perspective(float near, float far, float angle);
250 
251     bool operator==(const SkM44& other) const;
252     bool operator!=(const SkM44& other) const {
253         return !(other == *this);
254     }
255 
getColMajor(SkScalar v[])256     void getColMajor(SkScalar v[]) const {
257         memcpy(v, fMat, sizeof(fMat));
258     }
259     void getRowMajor(SkScalar v[]) const;
260 
rc(int r,int c)261     SkScalar rc(int r, int c) const {
262         SkASSERT(r >= 0 && r <= 3);
263         SkASSERT(c >= 0 && c <= 3);
264         return fMat[c*4 + r];
265     }
setRC(int r,int c,SkScalar value)266     void setRC(int r, int c, SkScalar value) {
267         SkASSERT(r >= 0 && r <= 3);
268         SkASSERT(c >= 0 && c <= 3);
269         fMat[c*4 + r] = value;
270     }
271 
row(int i)272     SkV4 row(int i) const {
273         SkASSERT(i >= 0 && i <= 3);
274         return {fMat[i + 0], fMat[i + 4], fMat[i + 8], fMat[i + 12]};
275     }
col(int i)276     SkV4 col(int i) const {
277         SkASSERT(i >= 0 && i <= 3);
278         return {fMat[i*4 + 0], fMat[i*4 + 1], fMat[i*4 + 2], fMat[i*4 + 3]};
279     }
280 
setRow(int i,const SkV4 & v)281     void setRow(int i, const SkV4& v) {
282         SkASSERT(i >= 0 && i <= 3);
283         fMat[i + 0]  = v.x;
284         fMat[i + 4]  = v.y;
285         fMat[i + 8]  = v.z;
286         fMat[i + 12] = v.w;
287     }
setCol(int i,const SkV4 & v)288     void setCol(int i, const SkV4& v) {
289         SkASSERT(i >= 0 && i <= 3);
290         memcpy(&fMat[i*4], v.ptr(), sizeof(v));
291     }
292 
setIdentity()293     SkM44& setIdentity() {
294         *this = { 1, 0, 0, 0,
295                   0, 1, 0, 0,
296                   0, 0, 1, 0,
297                   0, 0, 0, 1 };
298         return *this;
299     }
300 
301     SkM44& setTranslate(SkScalar x, SkScalar y, SkScalar z = 0) {
302         *this = { 1, 0, 0, x,
303                   0, 1, 0, y,
304                   0, 0, 1, z,
305                   0, 0, 0, 1 };
306         return *this;
307     }
308 
309     SkM44& setScale(SkScalar x, SkScalar y, SkScalar z = 1) {
310         *this = { x, 0, 0, 0,
311                   0, y, 0, 0,
312                   0, 0, z, 0,
313                   0, 0, 0, 1 };
314         return *this;
315     }
316 
317     /**
318      *  Set this matrix to rotate about the specified unit-length axis vector,
319      *  by an angle specified by its sin() and cos().
320      *
321      *  This does not attempt to verify that axis.length() == 1 or that the sin,cos values
322      *  are correct.
323      */
324     SkM44& setRotateUnitSinCos(SkV3 axis, SkScalar sinAngle, SkScalar cosAngle);
325 
326     /**
327      *  Set this matrix to rotate about the specified unit-length axis vector,
328      *  by an angle specified in radians.
329      *
330      *  This does not attempt to verify that axis.length() == 1.
331      */
setRotateUnit(SkV3 axis,SkScalar radians)332     SkM44& setRotateUnit(SkV3 axis, SkScalar radians) {
333         return this->setRotateUnitSinCos(axis, SkScalarSin(radians), SkScalarCos(radians));
334     }
335 
336     /**
337      *  Set this matrix to rotate about the specified axis vector,
338      *  by an angle specified in radians.
339      *
340      *  Note: axis is not assumed to be unit-length, so it will be normalized internally.
341      *        If axis is already unit-length, call setRotateAboutUnitRadians() instead.
342      */
343     SkM44& setRotate(SkV3 axis, SkScalar radians);
344 
345     SkM44& setConcat(const SkM44& a, const SkM44& b);
346 
347     friend SkM44 operator*(const SkM44& a, const SkM44& b) {
348         return SkM44(a, b);
349     }
350 
preConcat(const SkM44 & m)351     SkM44& preConcat(const SkM44& m) {
352         return this->setConcat(*this, m);
353     }
354 
postConcat(const SkM44 & m)355     SkM44& postConcat(const SkM44& m) {
356         return this->setConcat(m, *this);
357     }
358 
359     /**
360      *  A matrix is categorized as 'perspective' if the bottom row is not [0, 0, 0, 1].
361      *  For most uses, a bottom row of [0, 0, 0, X] behaves like a non-perspective matrix, though
362      *  it will be categorized as perspective. Calling normalizePerspective() will change the
363      *  matrix such that, if its bottom row was [0, 0, 0, X], it will be changed to [0, 0, 0, 1]
364      *  by scaling the rest of the matrix by 1/X.
365      *
366      *  | A B C D |    | A/X B/X C/X D/X |
367      *  | E F G H | -> | E/X F/X G/X H/X |   for X != 0
368      *  | I J K L |    | I/X J/X K/X L/X |
369      *  | 0 0 0 X |    |  0   0   0   1  |
370      */
371     void normalizePerspective();
372 
373     /** Returns true if all elements of the matrix are finite. Returns false if any
374         element is infinity, or NaN.
375 
376         @return  true if matrix has only finite elements
377     */
isFinite()378     bool isFinite() const { return SkIsFinite(fMat, 16); }
379 
380     /** If this is invertible, return that in inverse and return true. If it is
381      *  not invertible, return false and leave the inverse parameter unchanged.
382      */
383     [[nodiscard]] bool invert(SkM44* inverse) const;
384 
385     [[nodiscard]] SkM44 transpose() const;
386 
387     void dump() const;
388 
389     ////////////
390 
391     SkV4 map(float x, float y, float z, float w) const;
392     SkV4 operator*(const SkV4& v) const {
393         return this->map(v.x, v.y, v.z, v.w);
394     }
395     SkV3 operator*(SkV3 v) const {
396         auto v4 = this->map(v.x, v.y, v.z, 0);
397         return {v4.x, v4.y, v4.z};
398     }
399     ////////////////////// Converting to/from SkMatrix
400 
401     /* When converting from SkM44 to SkMatrix, the third row and
402      * column is dropped.  When converting from SkMatrix to SkM44
403      * the third row and column remain as identity:
404      * [ a b c ]      [ a b 0 c ]
405      * [ d e f ]  ->  [ d e 0 f ]
406      * [ g h i ]      [ 0 0 1 0 ]
407      *                [ g h 0 i ]
408      */
asM33()409     SkMatrix asM33() const {
410         return SkMatrix::MakeAll(fMat[0], fMat[4], fMat[12],
411                                  fMat[1], fMat[5], fMat[13],
412                                  fMat[3], fMat[7], fMat[15]);
413     }
414 
SkM44(const SkMatrix & src)415     explicit SkM44(const SkMatrix& src)
416     : SkM44(src[SkMatrix::kMScaleX], src[SkMatrix::kMSkewX],  0, src[SkMatrix::kMTransX],
417             src[SkMatrix::kMSkewY],  src[SkMatrix::kMScaleY], 0, src[SkMatrix::kMTransY],
418             0,                       0,                       1, 0,
419             src[SkMatrix::kMPersp0], src[SkMatrix::kMPersp1], 0, src[SkMatrix::kMPersp2])
420     {}
421 
422     SkM44& preTranslate(SkScalar x, SkScalar y, SkScalar z = 0);
423     SkM44& postTranslate(SkScalar x, SkScalar y, SkScalar z = 0);
424 
425     SkM44& preScale(SkScalar x, SkScalar y);
426     SkM44& preScale(SkScalar x, SkScalar y, SkScalar z);
427     SkM44& preConcat(const SkMatrix&);
428 
429 private:
430     /* Stored in column-major.
431      *  Indices
432      *  0  4  8  12        1 0 0 trans_x
433      *  1  5  9  13  e.g.  0 1 0 trans_y
434      *  2  6 10  14        0 0 1 trans_z
435      *  3  7 11  15        0 0 0 1
436      */
437     SkScalar fMat[16];
438 
439     friend class SkMatrixPriv;
440 };
441 
442 #endif
443