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