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