2 * Copyright 2011 Google Inc.
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
8 #ifndef SkMatrix44_DEFINED
9 #define SkMatrix44_DEFINED
14 #ifdef SK_MSCALAR_IS_DOUBLE
15 #ifdef SK_MSCALAR_IS_FLOAT
16 #error "can't define MSCALAR both as DOUBLE and FLOAT"
18 typedef double SkMScalar;
20 static inline double SkFloatToMScalar(float x) {
21 return static_cast<double>(x);
23 static inline float SkMScalarToFloat(double x) {
24 return static_cast<float>(x);
26 static inline double SkDoubleToMScalar(double x) {
29 static inline double SkMScalarToDouble(double x) {
32 static inline double SkMScalarAbs(double x) {
35 static const SkMScalar SK_MScalarPI = 3.141592653589793;
37 #define SkMScalarFloor(x) sk_double_floor(x)
38 #define SkMScalarCeil(x) sk_double_ceil(x)
39 #define SkMScalarRound(x) sk_double_round(x)
41 #define SkMScalarFloorToInt(x) sk_double_floor2int(x)
42 #define SkMScalarCeilToInt(x) sk_double_ceil2int(x)
43 #define SkMScalarRoundToInt(x) sk_double_round2int(x)
46 #elif defined SK_MSCALAR_IS_FLOAT
47 #ifdef SK_MSCALAR_IS_DOUBLE
48 #error "can't define MSCALAR both as DOUBLE and FLOAT"
50 typedef float SkMScalar;
52 static inline float SkFloatToMScalar(float x) {
55 static inline float SkMScalarToFloat(float x) {
58 static inline float SkDoubleToMScalar(double x) {
59 return static_cast<float>(x);
61 static inline double SkMScalarToDouble(float x) {
62 return static_cast<double>(x);
64 static inline float SkMScalarAbs(float x) {
65 return sk_float_abs(x);
67 static const SkMScalar SK_MScalarPI = 3.14159265f;
69 #define SkMScalarFloor(x) sk_float_floor(x)
70 #define SkMScalarCeil(x) sk_float_ceil(x)
71 #define SkMScalarRound(x) sk_float_round(x)
73 #define SkMScalarFloorToInt(x) sk_float_floor2int(x)
74 #define SkMScalarCeilToInt(x) sk_float_ceil2int(x)
75 #define SkMScalarRoundToInt(x) sk_float_round2int(x)
79 #define SkIntToMScalar(n) static_cast<SkMScalar>(n)
81 #define SkMScalarToScalar(x) SkMScalarToFloat(x)
82 #define SkScalarToMScalar(x) SkFloatToMScalar(x)
84 static const SkMScalar SK_MScalar1 = 1;
86 ///////////////////////////////////////////////////////////////////////////////
92 this->set(0, 0, 0, 1);
94 SkVector4(const SkVector4& src) {
95 memcpy(fData, src.fData, sizeof(fData));
97 SkVector4(SkScalar x, SkScalar y, SkScalar z, SkScalar w = SK_Scalar1) {
104 SkVector4& operator=(const SkVector4& src) {
105 memcpy(fData, src.fData, sizeof(fData));
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];
113 bool operator!=(const SkVector4& v) {
114 return !(*this == v);
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;
121 void set(SkScalar x, SkScalar y, SkScalar z, SkScalar w = SK_Scalar1) {
129 class SK_API SkMatrix44 {
132 enum Uninitialized_Constructor {
133 kUninitialized_Constructor
135 enum Identity_Constructor {
136 kIdentity_Constructor
139 SkMatrix44(Uninitialized_Constructor) { }
140 SkMatrix44(Identity_Constructor) { this->setIdentity(); }
142 SK_ATTR_DEPRECATED("use the constructors that take an enum")
143 SkMatrix44() { this->setIdentity(); }
145 SkMatrix44(const SkMatrix44& src) {
146 memcpy(fMat, src.fMat, sizeof(fMat));
147 fTypeMask = src.fTypeMask;
150 SkMatrix44(const SkMatrix44& a, const SkMatrix44& b) {
151 this->setConcat(a, b);
154 SkMatrix44& operator=(const SkMatrix44& src) {
156 memcpy(fMat, src.fMat, sizeof(fMat));
157 fTypeMask = src.fTypeMask;
162 bool operator==(const SkMatrix44& other) const;
163 bool operator!=(const SkMatrix44& other) const {
164 return !(other == *this);
167 /* When converting from SkMatrix44 to SkMatrix, the third row and
168 * column is dropped. When converting from SkMatrix to SkMatrix44
169 * the third row and column remain as identity:
170 * [ a b c ] [ a b 0 c ]
171 * [ d e f ] -> [ d e 0 f ]
172 * [ g h i ] [ 0 0 1 0 ]
175 SkMatrix44(const SkMatrix&);
176 SkMatrix44& operator=(const SkMatrix& src);
177 operator SkMatrix() const;
180 * Return a reference to a const identity matrix
182 static const SkMatrix44& I();
186 kTranslate_Mask = 0x01, //!< set if the matrix has translation
187 kScale_Mask = 0x02, //!< set if the matrix has any scale != 1
188 kAffine_Mask = 0x04, //!< set if the matrix skews or rotates
189 kPerspective_Mask = 0x08 //!< set if the matrix is in perspective
193 * Returns a bitfield describing the transformations the matrix may
194 * perform. The bitfield is computed conservatively, so it may include
195 * false positives. For example, when kPerspective_Mask is true, all
196 * other bits may be set to true even in the case of a pure perspective
199 inline TypeMask getType() const {
200 if (fTypeMask & kUnknown_Mask) {
201 fTypeMask = this->computeTypeMask();
203 SkASSERT(!(fTypeMask & kUnknown_Mask));
204 return (TypeMask)fTypeMask;
208 * Return true if the matrix is identity.
210 inline bool isIdentity() const {
211 return kIdentity_Mask == this->getType();
215 * Return true if the matrix contains translate or is identity.
217 inline bool isTranslate() const {
218 return !(this->getType() & ~kTranslate_Mask);
222 * Return true if the matrix only contains scale or translate or is identity.
224 inline bool isScaleTranslate() const {
225 return !(this->getType() & ~(kScale_Mask | kTranslate_Mask));
229 * Returns true if the matrix only contains scale or is identity.
231 inline bool isScale() const {
232 return !(this->getType() & ~kScale_Mask);
235 inline bool hasPerspective() const {
236 return SkToBool(this->getType() & kPerspective_Mask);
240 inline void reset() { this->setIdentity();}
243 * get a value from the matrix. The row,col parameters work as follows:
246 * (3, 0) perspective-x
248 inline SkMScalar get(int row, int col) const {
249 SkASSERT((unsigned)row <= 3);
250 SkASSERT((unsigned)col <= 3);
251 return fMat[col][row];
255 * set a value in the matrix. The row,col parameters work as follows:
258 * (3, 0) perspective-x
260 inline void set(int row, int col, SkMScalar value) {
261 SkASSERT((unsigned)row <= 3);
262 SkASSERT((unsigned)col <= 3);
263 fMat[col][row] = value;
264 this->dirtyTypeMask();
267 inline double getDouble(int row, int col) const {
268 return SkMScalarToDouble(this->get(row, col));
270 inline void setDouble(int row, int col, double value) {
271 this->set(row, col, SkDoubleToMScalar(value));
273 inline float getFloat(int row, int col) const {
274 return SkMScalarToFloat(this->get(row, col));
276 inline void setFloat(int row, int col, float value) {
277 this->set(row, col, SkFloatToMScalar(value));
280 /** These methods allow one to efficiently read matrix entries into an
281 * array. The given array must have room for exactly 16 entries. Whenever
282 * possible, they will try to use memcpy rather than an entry-by-entry
285 void asColMajorf(float[]) const;
286 void asColMajord(double[]) const;
287 void asRowMajorf(float[]) const;
288 void asRowMajord(double[]) const;
290 /** These methods allow one to efficiently set all matrix entries from an
291 * array. The given array must have room for exactly 16 entries. Whenever
292 * possible, they will try to use memcpy rather than an entry-by-entry
295 void setColMajorf(const float[]);
296 void setColMajord(const double[]);
297 void setRowMajorf(const float[]);
298 void setRowMajord(const double[]);
300 #ifdef SK_MSCALAR_IS_FLOAT
301 void setColMajor(const SkMScalar data[]) { this->setColMajorf(data); }
302 void setRowMajor(const SkMScalar data[]) { this->setRowMajorf(data); }
304 void setColMajor(const SkMScalar data[]) { this->setColMajord(data); }
305 void setRowMajor(const SkMScalar data[]) { this->setRowMajord(data); }
308 /* This sets the top-left of the matrix and clears the translation and
309 * perspective components (with [3][3] set to 1). */
310 void set3x3(SkMScalar m00, SkMScalar m01, SkMScalar m02,
311 SkMScalar m10, SkMScalar m11, SkMScalar m12,
312 SkMScalar m20, SkMScalar m21, SkMScalar m22);
314 void setTranslate(SkMScalar dx, SkMScalar dy, SkMScalar dz);
315 void preTranslate(SkMScalar dx, SkMScalar dy, SkMScalar dz);
316 void postTranslate(SkMScalar dx, SkMScalar dy, SkMScalar dz);
318 void setScale(SkMScalar sx, SkMScalar sy, SkMScalar sz);
319 void preScale(SkMScalar sx, SkMScalar sy, SkMScalar sz);
320 void postScale(SkMScalar sx, SkMScalar sy, SkMScalar sz);
322 inline void setScale(SkMScalar scale) {
323 this->setScale(scale, scale, scale);
325 inline void preScale(SkMScalar scale) {
326 this->preScale(scale, scale, scale);
328 inline void postScale(SkMScalar scale) {
329 this->postScale(scale, scale, scale);
332 void setRotateDegreesAbout(SkMScalar x, SkMScalar y, SkMScalar z,
334 this->setRotateAbout(x, y, z, degrees * SK_MScalarPI / 180);
337 /** Rotate about the vector [x,y,z]. If that vector is not unit-length,
338 it will be automatically resized.
340 void setRotateAbout(SkMScalar x, SkMScalar y, SkMScalar z,
342 /** Rotate about the vector [x,y,z]. Does not check the length of the
343 vector, assuming it is unit-length.
345 void setRotateAboutUnit(SkMScalar x, SkMScalar y, SkMScalar z,
348 void setConcat(const SkMatrix44& a, const SkMatrix44& b);
349 inline void preConcat(const SkMatrix44& m) {
350 this->setConcat(*this, m);
352 inline void postConcat(const SkMatrix44& m) {
353 this->setConcat(m, *this);
356 friend SkMatrix44 operator*(const SkMatrix44& a, const SkMatrix44& b) {
357 return SkMatrix44(a, b);
360 /** If this is invertible, return that in inverse and return true. If it is
361 not invertible, return false and ignore the inverse parameter.
363 bool invert(SkMatrix44* inverse) const;
365 /** Transpose this matrix in place. */
368 /** Apply the matrix to the src vector, returning the new vector in dst.
369 It is legal for src and dst to point to the same memory.
371 void mapScalars(const SkScalar src[4], SkScalar dst[4]) const;
372 inline void mapScalars(SkScalar vec[4]) const {
373 this->mapScalars(vec, vec);
376 SK_ATTR_DEPRECATED("use mapScalars")
377 void map(const SkScalar src[4], SkScalar dst[4]) const {
378 this->mapScalars(src, dst);
381 SK_ATTR_DEPRECATED("use mapScalars")
382 void map(SkScalar vec[4]) const {
383 this->mapScalars(vec, vec);
386 #ifdef SK_MSCALAR_IS_DOUBLE
387 void mapMScalars(const SkMScalar src[4], SkMScalar dst[4]) const;
388 #elif defined SK_MSCALAR_IS_FLOAT
389 inline void mapMScalars(const SkMScalar src[4], SkMScalar dst[4]) const {
390 this->mapScalars(src, dst);
393 inline void mapMScalars(SkMScalar vec[4]) const {
394 this->mapMScalars(vec, vec);
397 friend SkVector4 operator*(const SkMatrix44& m, const SkVector4& src) {
399 m.mapScalars(src.fData, dst.fData);
404 * map an array of [x, y, 0, 1] through the matrix, returning an array
405 * of [x', y', z', w'].
407 * @param src2 array of [x, y] pairs, with implied z=0 and w=1
408 * @param count number of [x, y] pairs in src2
409 * @param dst4 array of [x', y', z', w'] quads as the output.
411 void map2(const float src2[], int count, float dst4[]) const;
412 void map2(const double src2[], int count, double dst4[]) const;
414 /** Returns true if transformating an axis-aligned square in 2d by this matrix
415 will produce another 2d axis-aligned square; typically means the matrix
416 is a scale with perhaps a 90-degree rotation. A 3d rotation through 90
417 degrees into a perpendicular plane collapses a square to a line, but
418 is still considered to be axis-aligned.
420 By default, tolerates very slight error due to float imprecisions;
421 a 90-degree rotation can still end up with 10^-17 of
422 "non-axis-aligned" result.
424 bool preserves2dAxisAlignment(SkMScalar epsilon = SK_ScalarNearlyZero) const;
428 double determinant() const;
431 SkMScalar fMat[4][4];
432 mutable unsigned fTypeMask;
435 kUnknown_Mask = 0x80,
437 kAllPublic_Masks = 0xF
440 SkMScalar transX() const { return fMat[3][0]; }
441 SkMScalar transY() const { return fMat[3][1]; }
442 SkMScalar transZ() const { return fMat[3][2]; }
444 SkMScalar scaleX() const { return fMat[0][0]; }
445 SkMScalar scaleY() const { return fMat[1][1]; }
446 SkMScalar scaleZ() const { return fMat[2][2]; }
448 SkMScalar perspX() const { return fMat[0][3]; }
449 SkMScalar perspY() const { return fMat[1][3]; }
450 SkMScalar perspZ() const { return fMat[2][3]; }
452 int computeTypeMask() const;
454 inline void dirtyTypeMask() {
455 fTypeMask = kUnknown_Mask;
458 inline void setTypeMask(int mask) {
459 SkASSERT(0 == (~(kAllPublic_Masks | kUnknown_Mask) & mask));
464 * Does not take the time to 'compute' the typemask. Only returns true if
465 * we already know that this matrix is identity.
467 inline bool isTriviallyIdentity() const {
468 return 0 == fTypeMask;