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