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