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