• Home
  • History
  • Annotate
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1  /*
2   * Copyright 2011 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 SkMatrix44_DEFINED
9  #define SkMatrix44_DEFINED
10  
11  #include "SkMatrix.h"
12  #include "SkScalar.h"
13  
14  #ifdef SK_MSCALAR_IS_DOUBLE
15  #ifdef SK_MSCALAR_IS_FLOAT
16      #error "can't define MSCALAR both as DOUBLE and FLOAT"
17  #endif
18      typedef double SkMScalar;
19  
SkFloatToMScalar(float x)20      static inline double SkFloatToMScalar(float x) {
21          return static_cast<double>(x);
22      }
SkMScalarToFloat(double x)23      static inline float SkMScalarToFloat(double x) {
24          return static_cast<float>(x);
25      }
SkDoubleToMScalar(double x)26      static inline double SkDoubleToMScalar(double x) {
27          return x;
28      }
SkMScalarToDouble(double x)29      static inline double SkMScalarToDouble(double x) {
30          return x;
31      }
SkMScalarAbs(double x)32      static inline double SkMScalarAbs(double x) {
33          return fabs(x);
34      }
35      static const SkMScalar SK_MScalarPI = 3.141592653589793;
36  
37      #define SkMScalarFloor(x)           sk_double_floor(x)
38      #define SkMScalarCeil(x)            sk_double_ceil(x)
39      #define SkMScalarRound(x)           sk_double_round(x)
40  
41      #define SkMScalarFloorToInt(x)      sk_double_floor2int(x)
42      #define SkMScalarCeilToInt(x)       sk_double_ceil2int(x)
43      #define SkMScalarRoundToInt(x)      sk_double_round2int(x)
44  
45  
46  #elif defined SK_MSCALAR_IS_FLOAT
47  #ifdef SK_MSCALAR_IS_DOUBLE
48      #error "can't define MSCALAR both as DOUBLE and FLOAT"
49  #endif
50      typedef float SkMScalar;
51  
SkFloatToMScalar(float x)52      static inline float SkFloatToMScalar(float x) {
53          return x;
54      }
SkMScalarToFloat(float x)55      static inline float SkMScalarToFloat(float x) {
56          return x;
57      }
SkDoubleToMScalar(double x)58      static inline float SkDoubleToMScalar(double x) {
59          return static_cast<float>(x);
60      }
SkMScalarToDouble(float x)61      static inline double SkMScalarToDouble(float x) {
62          return static_cast<double>(x);
63      }
SkMScalarAbs(float x)64      static inline float SkMScalarAbs(float x) {
65          return sk_float_abs(x);
66      }
67      static const SkMScalar SK_MScalarPI = 3.14159265f;
68  
69      #define SkMScalarFloor(x)           sk_float_floor(x)
70      #define SkMScalarCeil(x)            sk_float_ceil(x)
71      #define SkMScalarRound(x)           sk_float_round(x)
72  
73      #define SkMScalarFloorToInt(x)      sk_float_floor2int(x)
74      #define SkMScalarCeilToInt(x)       sk_float_ceil2int(x)
75      #define SkMScalarRoundToInt(x)      sk_float_round2int(x)
76  
77  #endif
78  
79  #define SkIntToMScalar(n)       static_cast<SkMScalar>(n)
80  
81  #define SkMScalarToScalar(x)    SkMScalarToFloat(x)
82  #define SkScalarToMScalar(x)    SkFloatToMScalar(x)
83  
84  static const SkMScalar SK_MScalar1 = 1;
85  
86  ///////////////////////////////////////////////////////////////////////////////
87  
88  struct SkVector4 {
89      SkScalar fData[4];
90  
SkVector4SkVector491      SkVector4() {
92          this->set(0, 0, 0, 1);
93      }
SkVector4SkVector494      SkVector4(const SkVector4& src) {
95          memcpy(fData, src.fData, sizeof(fData));
96      }
97      SkVector4(SkScalar x, SkScalar y, SkScalar z, SkScalar w = SK_Scalar1) {
98          fData[0] = x;
99          fData[1] = y;
100          fData[2] = z;
101          fData[3] = w;
102      }
103  
104      SkVector4& operator=(const SkVector4& src) {
105          memcpy(fData, src.fData, sizeof(fData));
106          return *this;
107      }
108  
109      bool operator==(const SkVector4& v) {
110          return fData[0] == v.fData[0] && fData[1] == v.fData[1] &&
111                 fData[2] == v.fData[2] && fData[3] == v.fData[3];
112      }
113      bool operator!=(const SkVector4& v) {
114          return !(*this == v);
115      }
116      bool equals(SkScalar x, SkScalar y, SkScalar z, SkScalar w = SK_Scalar1) {
117          return fData[0] == x && fData[1] == y &&
118                 fData[2] == z && fData[3] == w;
119      }
120  
121      void set(SkScalar x, SkScalar y, SkScalar z, SkScalar w = SK_Scalar1) {
122          fData[0] = x;
123          fData[1] = y;
124          fData[2] = z;
125          fData[3] = w;
126      }
127  };
128  
129  /** \class SkMatrix44
130  
131      The SkMatrix44 class holds a 4x4 matrix.
132  
133      SkMatrix44 is not thread safe unless you've first called SkMatrix44::getType().
134  */
135  class SK_API SkMatrix44 {
136  public:
137  
138      enum Uninitialized_Constructor {
139          kUninitialized_Constructor
140      };
141      enum Identity_Constructor {
142          kIdentity_Constructor
143      };
144  
SkMatrix44(Uninitialized_Constructor)145      SkMatrix44(Uninitialized_Constructor) {}
146  
SkMatrix44(Identity_Constructor)147      constexpr SkMatrix44(Identity_Constructor)
148          : fMat{{ 1, 0, 0, 0, },
149                 { 0, 1, 0, 0, },
150                 { 0, 0, 1, 0, },
151                 { 0, 0, 0, 1, }}
152          , fTypeMask(kIdentity_Mask)
153      {}
154  
155      SK_ATTR_DEPRECATED("use the constructors that take an enum")
SkMatrix44()156      SkMatrix44() { this->setIdentity(); }
157  
SkMatrix44(const SkMatrix44 & src)158      SkMatrix44(const SkMatrix44& src) {
159          memcpy(fMat, src.fMat, sizeof(fMat));
160          fTypeMask = src.fTypeMask;
161      }
162  
SkMatrix44(const SkMatrix44 & a,const SkMatrix44 & b)163      SkMatrix44(const SkMatrix44& a, const SkMatrix44& b) {
164          this->setConcat(a, b);
165      }
166  
167      SkMatrix44& operator=(const SkMatrix44& src) {
168          if (&src != this) {
169              memcpy(fMat, src.fMat, sizeof(fMat));
170              fTypeMask = src.fTypeMask;
171          }
172          return *this;
173      }
174  
175      bool operator==(const SkMatrix44& other) const;
176      bool operator!=(const SkMatrix44& other) const {
177          return !(other == *this);
178      }
179  
180      /* When converting from SkMatrix44 to SkMatrix, the third row and
181       * column is dropped.  When converting from SkMatrix to SkMatrix44
182       * the third row and column remain as identity:
183       * [ a b c ]      [ a b 0 c ]
184       * [ d e f ]  ->  [ d e 0 f ]
185       * [ g h i ]      [ 0 0 1 0 ]
186       *                [ g h 0 i ]
187       */
188      SkMatrix44(const SkMatrix&);
189      SkMatrix44& operator=(const SkMatrix& src);
190      operator SkMatrix() const;
191  
192      /**
193       *  Return a reference to a const identity matrix
194       */
195      static const SkMatrix44& I();
196  
197      enum TypeMask {
198          kIdentity_Mask      = 0,
199          kTranslate_Mask     = 0x01,  //!< set if the matrix has translation
200          kScale_Mask         = 0x02,  //!< set if the matrix has any scale != 1
201          kAffine_Mask        = 0x04,  //!< set if the matrix skews or rotates
202          kPerspective_Mask   = 0x08   //!< set if the matrix is in perspective
203      };
204  
205      /**
206       *  Returns a bitfield describing the transformations the matrix may
207       *  perform. The bitfield is computed conservatively, so it may include
208       *  false positives. For example, when kPerspective_Mask is true, all
209       *  other bits may be set to true even in the case of a pure perspective
210       *  transform.
211       */
getType()212      inline TypeMask getType() const {
213          if (fTypeMask & kUnknown_Mask) {
214              fTypeMask = this->computeTypeMask();
215          }
216          SkASSERT(!(fTypeMask & kUnknown_Mask));
217          return (TypeMask)fTypeMask;
218      }
219  
220      /**
221       *  Return true if the matrix is identity.
222       */
isIdentity()223      inline bool isIdentity() const {
224          return kIdentity_Mask == this->getType();
225      }
226  
227      /**
228       *  Return true if the matrix contains translate or is identity.
229       */
isTranslate()230      inline bool isTranslate() const {
231          return !(this->getType() & ~kTranslate_Mask);
232      }
233  
234      /**
235       *  Return true if the matrix only contains scale or translate or is identity.
236       */
isScaleTranslate()237      inline bool isScaleTranslate() const {
238          return !(this->getType() & ~(kScale_Mask | kTranslate_Mask));
239      }
240  
241      /**
242       *  Returns true if the matrix only contains scale or is identity.
243       */
isScale()244      inline bool isScale() const {
245              return !(this->getType() & ~kScale_Mask);
246      }
247  
hasPerspective()248      inline bool hasPerspective() const {
249          return SkToBool(this->getType() & kPerspective_Mask);
250      }
251  
252      void setIdentity();
reset()253      inline void reset() { this->setIdentity();}
254  
255      /**
256       *  get a value from the matrix. The row,col parameters work as follows:
257       *  (0, 0)  scale-x
258       *  (0, 3)  translate-x
259       *  (3, 0)  perspective-x
260       */
get(int row,int col)261      inline SkMScalar get(int row, int col) const {
262          SkASSERT((unsigned)row <= 3);
263          SkASSERT((unsigned)col <= 3);
264          return fMat[col][row];
265      }
266  
267      /**
268       *  set a value in the matrix. The row,col parameters work as follows:
269       *  (0, 0)  scale-x
270       *  (0, 3)  translate-x
271       *  (3, 0)  perspective-x
272       */
set(int row,int col,SkMScalar value)273      inline void set(int row, int col, SkMScalar value) {
274          SkASSERT((unsigned)row <= 3);
275          SkASSERT((unsigned)col <= 3);
276          fMat[col][row] = value;
277          this->dirtyTypeMask();
278      }
279  
getDouble(int row,int col)280      inline double getDouble(int row, int col) const {
281          return SkMScalarToDouble(this->get(row, col));
282      }
setDouble(int row,int col,double value)283      inline void setDouble(int row, int col, double value) {
284          this->set(row, col, SkDoubleToMScalar(value));
285      }
getFloat(int row,int col)286      inline float getFloat(int row, int col) const {
287          return SkMScalarToFloat(this->get(row, col));
288      }
setFloat(int row,int col,float value)289      inline void setFloat(int row, int col, float value) {
290          this->set(row, col, SkFloatToMScalar(value));
291      }
292  
293      /** These methods allow one to efficiently read matrix entries into an
294       *  array. The given array must have room for exactly 16 entries. Whenever
295       *  possible, they will try to use memcpy rather than an entry-by-entry
296       *  copy.
297       *
298       *  Col major indicates that consecutive elements of columns will be stored
299       *  contiguously in memory.  Row major indicates that consecutive elements
300       *  of rows will be stored contiguously in memory.
301       */
302      void asColMajorf(float[]) const;
303      void asColMajord(double[]) const;
304      void asRowMajorf(float[]) const;
305      void asRowMajord(double[]) const;
306  
307      /** These methods allow one to efficiently set all matrix entries from an
308       *  array. The given array must have room for exactly 16 entries. Whenever
309       *  possible, they will try to use memcpy rather than an entry-by-entry
310       *  copy.
311       *
312       *  Col major indicates that input memory will be treated as if consecutive
313       *  elements of columns are stored contiguously in memory.  Row major
314       *  indicates that input memory will be treated as if consecutive elements
315       *  of rows are stored contiguously in memory.
316       */
317      void setColMajorf(const float[]);
318      void setColMajord(const double[]);
319      void setRowMajorf(const float[]);
320      void setRowMajord(const double[]);
321  
322  #ifdef SK_MSCALAR_IS_FLOAT
setColMajor(const SkMScalar data[])323      void setColMajor(const SkMScalar data[]) { this->setColMajorf(data); }
setRowMajor(const SkMScalar data[])324      void setRowMajor(const SkMScalar data[]) { this->setRowMajorf(data); }
325  #else
setColMajor(const SkMScalar data[])326      void setColMajor(const SkMScalar data[]) { this->setColMajord(data); }
setRowMajor(const SkMScalar data[])327      void setRowMajor(const SkMScalar data[]) { this->setRowMajord(data); }
328  #endif
329  
330      /* This sets the top-left of the matrix and clears the translation and
331       * perspective components (with [3][3] set to 1).  mXY is interpreted
332       * as the matrix entry at col = X, row = Y. */
333      void set3x3(SkMScalar m00, SkMScalar m01, SkMScalar m02,
334                  SkMScalar m10, SkMScalar m11, SkMScalar m12,
335                  SkMScalar m20, SkMScalar m21, SkMScalar m22);
336      void set3x3RowMajorf(const float[]);
337  
338      void setTranslate(SkMScalar dx, SkMScalar dy, SkMScalar dz);
339      void preTranslate(SkMScalar dx, SkMScalar dy, SkMScalar dz);
340      void postTranslate(SkMScalar dx, SkMScalar dy, SkMScalar dz);
341  
342      void setScale(SkMScalar sx, SkMScalar sy, SkMScalar sz);
343      void preScale(SkMScalar sx, SkMScalar sy, SkMScalar sz);
344      void postScale(SkMScalar sx, SkMScalar sy, SkMScalar sz);
345  
setScale(SkMScalar scale)346      inline void setScale(SkMScalar scale) {
347          this->setScale(scale, scale, scale);
348      }
preScale(SkMScalar scale)349      inline void preScale(SkMScalar scale) {
350          this->preScale(scale, scale, scale);
351      }
postScale(SkMScalar scale)352      inline void postScale(SkMScalar scale) {
353          this->postScale(scale, scale, scale);
354      }
355  
setRotateDegreesAbout(SkMScalar x,SkMScalar y,SkMScalar z,SkMScalar degrees)356      void setRotateDegreesAbout(SkMScalar x, SkMScalar y, SkMScalar z,
357                                 SkMScalar degrees) {
358          this->setRotateAbout(x, y, z, degrees * SK_MScalarPI / 180);
359      }
360  
361      /** Rotate about the vector [x,y,z]. If that vector is not unit-length,
362          it will be automatically resized.
363       */
364      void setRotateAbout(SkMScalar x, SkMScalar y, SkMScalar z,
365                          SkMScalar radians);
366      /** Rotate about the vector [x,y,z]. Does not check the length of the
367          vector, assuming it is unit-length.
368       */
369      void setRotateAboutUnit(SkMScalar x, SkMScalar y, SkMScalar z,
370                              SkMScalar radians);
371  
372      void setConcat(const SkMatrix44& a, const SkMatrix44& b);
preConcat(const SkMatrix44 & m)373      inline void preConcat(const SkMatrix44& m) {
374          this->setConcat(*this, m);
375      }
postConcat(const SkMatrix44 & m)376      inline void postConcat(const SkMatrix44& m) {
377          this->setConcat(m, *this);
378      }
379  
380      friend SkMatrix44 operator*(const SkMatrix44& a, const SkMatrix44& b) {
381          return SkMatrix44(a, b);
382      }
383  
384      /** If this is invertible, return that in inverse and return true. If it is
385          not invertible, return false and leave the inverse parameter in an
386          unspecified state.
387       */
388      bool invert(SkMatrix44* inverse) const;
389  
390      /** Transpose this matrix in place. */
391      void transpose();
392  
393      /** Apply the matrix to the src vector, returning the new vector in dst.
394          It is legal for src and dst to point to the same memory.
395       */
396      void mapScalars(const SkScalar src[4], SkScalar dst[4]) const;
mapScalars(SkScalar vec[4])397      inline void mapScalars(SkScalar vec[4]) const {
398          this->mapScalars(vec, vec);
399      }
400  
401      SK_ATTR_DEPRECATED("use mapScalars")
map(const SkScalar src[4],SkScalar dst[4])402      void map(const SkScalar src[4], SkScalar dst[4]) const {
403          this->mapScalars(src, dst);
404      }
405  
406      SK_ATTR_DEPRECATED("use mapScalars")
map(SkScalar vec[4])407      void map(SkScalar vec[4]) const {
408          this->mapScalars(vec, vec);
409      }
410  
411  #ifdef SK_MSCALAR_IS_DOUBLE
412      void mapMScalars(const SkMScalar src[4], SkMScalar dst[4]) const;
413  #elif defined SK_MSCALAR_IS_FLOAT
mapMScalars(const SkMScalar src[4],SkMScalar dst[4])414      inline void mapMScalars(const SkMScalar src[4], SkMScalar dst[4]) const {
415          this->mapScalars(src, dst);
416      }
417  #endif
mapMScalars(SkMScalar vec[4])418      inline void mapMScalars(SkMScalar vec[4]) const {
419          this->mapMScalars(vec, vec);
420      }
421  
422      friend SkVector4 operator*(const SkMatrix44& m, const SkVector4& src) {
423          SkVector4 dst;
424          m.mapScalars(src.fData, dst.fData);
425          return dst;
426      }
427  
428      /**
429       *  map an array of [x, y, 0, 1] through the matrix, returning an array
430       *  of [x', y', z', w'].
431       *
432       *  @param src2     array of [x, y] pairs, with implied z=0 and w=1
433       *  @param count    number of [x, y] pairs in src2
434       *  @param dst4     array of [x', y', z', w'] quads as the output.
435       */
436      void map2(const float src2[], int count, float dst4[]) const;
437      void map2(const double src2[], int count, double dst4[]) const;
438  
439      /** Returns true if transformating an axis-aligned square in 2d by this matrix
440          will produce another 2d axis-aligned square; typically means the matrix
441          is a scale with perhaps a 90-degree rotation. A 3d rotation through 90
442          degrees into a perpendicular plane collapses a square to a line, but
443          is still considered to be axis-aligned.
444  
445          By default, tolerates very slight error due to float imprecisions;
446          a 90-degree rotation can still end up with 10^-17 of
447          "non-axis-aligned" result.
448       */
449      bool preserves2dAxisAlignment(SkMScalar epsilon = SK_ScalarNearlyZero) const;
450  
451      void dump() const;
452  
453      double determinant() const;
454  
455  private:
456      /* This is indexed by [col][row]. */
457      SkMScalar           fMat[4][4];
458      mutable unsigned    fTypeMask;
459  
460      enum {
461          kUnknown_Mask = 0x80,
462  
463          kAllPublic_Masks = 0xF
464      };
465  
466      void as3x4RowMajorf(float[]) const;
467      void set3x4RowMajorf(const float[]);
468  
transX()469      SkMScalar transX() const { return fMat[3][0]; }
transY()470      SkMScalar transY() const { return fMat[3][1]; }
transZ()471      SkMScalar transZ() const { return fMat[3][2]; }
472  
scaleX()473      SkMScalar scaleX() const { return fMat[0][0]; }
scaleY()474      SkMScalar scaleY() const { return fMat[1][1]; }
scaleZ()475      SkMScalar scaleZ() const { return fMat[2][2]; }
476  
perspX()477      SkMScalar perspX() const { return fMat[0][3]; }
perspY()478      SkMScalar perspY() const { return fMat[1][3]; }
perspZ()479      SkMScalar perspZ() const { return fMat[2][3]; }
480  
481      int computeTypeMask() const;
482  
dirtyTypeMask()483      inline void dirtyTypeMask() {
484          fTypeMask = kUnknown_Mask;
485      }
486  
setTypeMask(int mask)487      inline void setTypeMask(int mask) {
488          SkASSERT(0 == (~(kAllPublic_Masks | kUnknown_Mask) & mask));
489          fTypeMask = mask;
490      }
491  
492      /**
493       *  Does not take the time to 'compute' the typemask. Only returns true if
494       *  we already know that this matrix is identity.
495       */
isTriviallyIdentity()496      inline bool isTriviallyIdentity() const {
497          return 0 == fTypeMask;
498      }
499  
values()500      inline const SkMScalar* values() const { return &fMat[0][0]; }
501  
502      friend class SkColorSpace;
503      friend class SkColorSpace_XYZ;
504  };
505  
506  #endif
507