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