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 const SkMScalar SK_MScalarPI = 3.141592653589793;
33 #elif defined SK_MSCALAR_IS_FLOAT
34 #ifdef SK_MSCALAR_IS_DOUBLE
35 #error "can't define MSCALAR both as DOUBLE and FLOAT"
37 typedef float SkMScalar;
39 static inline float SkFloatToMScalar(float x) {
42 static inline float SkMScalarToFloat(float x) {
45 static inline float SkDoubleToMScalar(double x) {
46 return static_cast<float>(x);
48 static inline double SkMScalarToDouble(float x) {
49 return static_cast<double>(x);
51 static const SkMScalar SK_MScalarPI = 3.14159265f;
54 #define SkMScalarToScalar SkMScalarToFloat
55 #define SkScalarToMScalar SkFloatToMScalar
57 static const SkMScalar SK_MScalar1 = 1;
59 ///////////////////////////////////////////////////////////////////////////////
65 this->set(0, 0, 0, 1);
67 SkVector4(const SkVector4& src) {
68 memcpy(fData, src.fData, sizeof(fData));
70 SkVector4(SkScalar x, SkScalar y, SkScalar z, SkScalar w = SK_Scalar1) {
77 SkVector4& operator=(const SkVector4& src) {
78 memcpy(fData, src.fData, sizeof(fData));
82 bool operator==(const SkVector4& v) {
83 return fData[0] == v.fData[0] && fData[1] == v.fData[1] &&
84 fData[2] == v.fData[2] && fData[3] == v.fData[3];
86 bool operator!=(const SkVector4& v) {
89 bool equals(SkScalar x, SkScalar y, SkScalar z, SkScalar w = SK_Scalar1) {
90 return fData[0] == x && fData[1] == y &&
91 fData[2] == z && fData[3] == w;
94 void set(SkScalar x, SkScalar y, SkScalar z, SkScalar w = SK_Scalar1) {
102 class SK_API SkMatrix44 {
105 enum Uninitialized_Constructor {
106 kUninitialized_Constructor
108 enum Identity_Constructor {
109 kIdentity_Constructor
112 SkMatrix44(Uninitialized_Constructor) { }
113 SkMatrix44(Identity_Constructor) { this->setIdentity(); }
115 SK_ATTR_DEPRECATED("use the constructors that take an enum")
116 SkMatrix44() { this->setIdentity(); }
118 SkMatrix44(const SkMatrix44& src) {
119 memcpy(fMat, src.fMat, sizeof(fMat));
120 fTypeMask = src.fTypeMask;
123 SkMatrix44(const SkMatrix44& a, const SkMatrix44& b) {
124 this->setConcat(a, b);
127 SkMatrix44& operator=(const SkMatrix44& src) {
129 memcpy(fMat, src.fMat, sizeof(fMat));
130 fTypeMask = src.fTypeMask;
135 bool operator==(const SkMatrix44& other) const;
136 bool operator!=(const SkMatrix44& other) const {
137 return !(other == *this);
140 /* When converting from SkMatrix44 to SkMatrix, the third row and
141 * column is dropped. When converting from SkMatrix to SkMatrix44
142 * the third row and column remain as identity:
143 * [ a b c ] [ a b 0 c ]
144 * [ d e f ] -> [ d e 0 f ]
145 * [ g h i ] [ 0 0 1 0 ]
148 SkMatrix44(const SkMatrix&);
149 SkMatrix44& operator=(const SkMatrix& src);
150 operator SkMatrix() const;
153 * Return a reference to a const identity matrix
155 static const SkMatrix44& I();
159 kTranslate_Mask = 0x01, //!< set if the matrix has translation
160 kScale_Mask = 0x02, //!< set if the matrix has any scale != 1
161 kAffine_Mask = 0x04, //!< set if the matrix skews or rotates
162 kPerspective_Mask = 0x08 //!< set if the matrix is in perspective
166 * Returns a bitfield describing the transformations the matrix may
167 * perform. The bitfield is computed conservatively, so it may include
168 * false positives. For example, when kPerspective_Mask is true, all
169 * other bits may be set to true even in the case of a pure perspective
172 inline TypeMask getType() const {
173 if (fTypeMask & kUnknown_Mask) {
174 fTypeMask = this->computeTypeMask();
176 SkASSERT(!(fTypeMask & kUnknown_Mask));
177 return (TypeMask)fTypeMask;
181 * Return true if the matrix is identity.
183 inline bool isIdentity() const {
184 return kIdentity_Mask == this->getType();
188 * Return true if the matrix contains translate or is identity.
190 inline bool isTranslate() const {
191 return !(this->getType() & ~kTranslate_Mask);
195 * Return true if the matrix only contains scale or translate or is identity.
197 inline bool isScaleTranslate() const {
198 return !(this->getType() & ~(kScale_Mask | kTranslate_Mask));
201 inline bool hasPerspective() const {
202 return SkToBool(this->getType() & kPerspective_Mask);
206 inline void reset() { this->setIdentity();}
209 * get a value from the matrix. The row,col parameters work as follows:
212 * (3, 0) perspective-x
214 inline SkMScalar get(int row, int col) const {
215 SkASSERT((unsigned)row <= 3);
216 SkASSERT((unsigned)col <= 3);
217 return fMat[col][row];
221 * set a value in the matrix. The row,col parameters work as follows:
224 * (3, 0) perspective-x
226 inline void set(int row, int col, SkMScalar value) {
227 SkASSERT((unsigned)row <= 3);
228 SkASSERT((unsigned)col <= 3);
229 fMat[col][row] = value;
230 this->dirtyTypeMask();
233 inline double getDouble(int row, int col) const {
234 return SkMScalarToDouble(this->get(row, col));
236 inline void setDouble(int row, int col, double value) {
237 this->set(row, col, SkDoubleToMScalar(value));
239 inline float getFloat(int row, int col) const {
240 return SkMScalarToFloat(this->get(row, col));
242 inline void setFloat(int row, int col, float value) {
243 this->set(row, col, SkFloatToMScalar(value));
246 /** These methods allow one to efficiently read matrix entries into an
247 * array. The given array must have room for exactly 16 entries. Whenever
248 * possible, they will try to use memcpy rather than an entry-by-entry
251 void asColMajorf(float[]) const;
252 void asColMajord(double[]) const;
253 void asRowMajorf(float[]) const;
254 void asRowMajord(double[]) const;
256 /** These methods allow one to efficiently set all matrix entries from an
257 * array. The given array must have room for exactly 16 entries. Whenever
258 * possible, they will try to use memcpy rather than an entry-by-entry
261 void setColMajorf(const float[]);
262 void setColMajord(const double[]);
263 void setRowMajorf(const float[]);
264 void setRowMajord(const double[]);
266 #ifdef SK_MSCALAR_IS_FLOAT
267 void setColMajor(const SkMScalar data[]) { this->setColMajorf(data); }
268 void setRowMajor(const SkMScalar data[]) { this->setRowMajorf(data); }
270 void setColMajor(const SkMScalar data[]) { this->setColMajord(data); }
271 void setRowMajor(const SkMScalar data[]) { this->setRowMajord(data); }
274 /* This sets the top-left of the matrix and clears the translation and
275 * perspective components (with [3][3] set to 1). */
276 void set3x3(SkMScalar m00, SkMScalar m01, SkMScalar m02,
277 SkMScalar m10, SkMScalar m11, SkMScalar m12,
278 SkMScalar m20, SkMScalar m21, SkMScalar m22);
280 void setTranslate(SkMScalar dx, SkMScalar dy, SkMScalar dz);
281 void preTranslate(SkMScalar dx, SkMScalar dy, SkMScalar dz);
282 void postTranslate(SkMScalar dx, SkMScalar dy, SkMScalar dz);
284 void setScale(SkMScalar sx, SkMScalar sy, SkMScalar sz);
285 void preScale(SkMScalar sx, SkMScalar sy, SkMScalar sz);
286 void postScale(SkMScalar sx, SkMScalar sy, SkMScalar sz);
288 inline void setScale(SkMScalar scale) {
289 this->setScale(scale, scale, scale);
291 inline void preScale(SkMScalar scale) {
292 this->preScale(scale, scale, scale);
294 inline void postScale(SkMScalar scale) {
295 this->postScale(scale, scale, scale);
298 void setRotateDegreesAbout(SkMScalar x, SkMScalar y, SkMScalar z,
300 this->setRotateAbout(x, y, z, degrees * SK_MScalarPI / 180);
303 /** Rotate about the vector [x,y,z]. If that vector is not unit-length,
304 it will be automatically resized.
306 void setRotateAbout(SkMScalar x, SkMScalar y, SkMScalar z,
308 /** Rotate about the vector [x,y,z]. Does not check the length of the
309 vector, assuming it is unit-length.
311 void setRotateAboutUnit(SkMScalar x, SkMScalar y, SkMScalar z,
314 void setConcat(const SkMatrix44& a, const SkMatrix44& b);
315 inline void preConcat(const SkMatrix44& m) {
316 this->setConcat(*this, m);
318 inline void postConcat(const SkMatrix44& m) {
319 this->setConcat(m, *this);
322 friend SkMatrix44 operator*(const SkMatrix44& a, const SkMatrix44& b) {
323 return SkMatrix44(a, b);
326 /** If this is invertible, return that in inverse and return true. If it is
327 not invertible, return false and ignore the inverse parameter.
329 bool invert(SkMatrix44* inverse) const;
331 /** Transpose this matrix in place. */
334 /** Apply the matrix to the src vector, returning the new vector in dst.
335 It is legal for src and dst to point to the same memory.
337 void mapScalars(const SkScalar src[4], SkScalar dst[4]) const;
338 inline void mapScalars(SkScalar vec[4]) const {
339 this->mapScalars(vec, vec);
342 SK_ATTR_DEPRECATED("use mapScalars")
343 void map(const SkScalar src[4], SkScalar dst[4]) const {
344 this->mapScalars(src, dst);
347 SK_ATTR_DEPRECATED("use mapScalars")
348 void map(SkScalar vec[4]) const {
349 this->mapScalars(vec, vec);
352 #ifdef SK_MSCALAR_IS_DOUBLE
353 void mapMScalars(const SkMScalar src[4], SkMScalar dst[4]) const;
354 #elif defined SK_MSCALAR_IS_FLOAT
355 inline void mapMScalars(const SkMScalar src[4], SkMScalar dst[4]) const {
356 this->mapScalars(src, dst);
359 inline void mapMScalars(SkMScalar vec[4]) const {
360 this->mapMScalars(vec, vec);
363 friend SkVector4 operator*(const SkMatrix44& m, const SkVector4& src) {
365 m.mapScalars(src.fData, dst.fData);
370 * map an array of [x, y, 0, 1] through the matrix, returning an array
371 * of [x', y', z', w'].
373 * @param src2 array of [x, y] pairs, with implied z=0 and w=1
374 * @param count number of [x, y] pairs in src2
375 * @param dst4 array of [x', y', z', w'] quads as the output.
377 void map2(const float src2[], int count, float dst4[]) const;
378 void map2(const double src2[], int count, double dst4[]) const;
382 double determinant() const;
385 SkMScalar fMat[4][4];
386 mutable unsigned fTypeMask;
389 kUnknown_Mask = 0x80,
391 kAllPublic_Masks = 0xF
394 SkMScalar transX() const { return fMat[3][0]; }
395 SkMScalar transY() const { return fMat[3][1]; }
396 SkMScalar transZ() const { return fMat[3][2]; }
398 SkMScalar scaleX() const { return fMat[0][0]; }
399 SkMScalar scaleY() const { return fMat[1][1]; }
400 SkMScalar scaleZ() const { return fMat[2][2]; }
402 SkMScalar perspX() const { return fMat[0][3]; }
403 SkMScalar perspY() const { return fMat[1][3]; }
404 SkMScalar perspZ() const { return fMat[2][3]; }
406 int computeTypeMask() const;
408 inline void dirtyTypeMask() {
409 fTypeMask = kUnknown_Mask;
412 inline void setTypeMask(int mask) {
413 SkASSERT(0 == (~(kAllPublic_Masks | kUnknown_Mask) & mask));
418 * Does not take the time to 'compute' the typemask. Only returns true if
419 * we already know that this matrix is identity.
421 inline bool isTriviallyIdentity() const {
422 return 0 == fTypeMask;