| 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 | struct SkVector4 { | 
|---|
| 18 | SkScalar fData[4]; | 
|---|
| 19 |  | 
|---|
| 20 | SkVector4() { | 
|---|
| 21 | this->set(0, 0, 0, 1); | 
|---|
| 22 | } | 
|---|
| 23 | SkVector4(const SkVector4& src) { | 
|---|
| 24 | memcpy(fData, src.fData, sizeof(fData)); | 
|---|
| 25 | } | 
|---|
| 26 | SkVector4(SkScalar x, SkScalar y, SkScalar z, SkScalar w = SK_Scalar1) { | 
|---|
| 27 | fData[0] = x; | 
|---|
| 28 | fData[1] = y; | 
|---|
| 29 | fData[2] = z; | 
|---|
| 30 | fData[3] = w; | 
|---|
| 31 | } | 
|---|
| 32 |  | 
|---|
| 33 | SkVector4& operator=(const SkVector4& src) { | 
|---|
| 34 | memcpy(fData, src.fData, sizeof(fData)); | 
|---|
| 35 | return *this; | 
|---|
| 36 | } | 
|---|
| 37 |  | 
|---|
| 38 | bool operator==(const SkVector4& v) const { | 
|---|
| 39 | return fData[0] == v.fData[0] && fData[1] == v.fData[1] && | 
|---|
| 40 | fData[2] == v.fData[2] && fData[3] == v.fData[3]; | 
|---|
| 41 | } | 
|---|
| 42 | bool operator!=(const SkVector4& v) const { return !(*this == v); } | 
|---|
| 43 | bool equals(SkScalar x, SkScalar y, SkScalar z, SkScalar w = SK_Scalar1) { | 
|---|
| 44 | return fData[0] == x && fData[1] == y && | 
|---|
| 45 | fData[2] == z && fData[3] == w; | 
|---|
| 46 | } | 
|---|
| 47 |  | 
|---|
| 48 | void set(SkScalar x, SkScalar y, SkScalar z, SkScalar w = SK_Scalar1) { | 
|---|
| 49 | fData[0] = x; | 
|---|
| 50 | fData[1] = y; | 
|---|
| 51 | fData[2] = z; | 
|---|
| 52 | fData[3] = w; | 
|---|
| 53 | } | 
|---|
| 54 | }; | 
|---|
| 55 |  | 
|---|
| 56 | /** \class SkMatrix44 | 
|---|
| 57 |  | 
|---|
| 58 | The SkMatrix44 class holds a 4x4 matrix. | 
|---|
| 59 |  | 
|---|
| 60 | */ | 
|---|
| 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 |  | 
|---|
| 74 | SkMatrix44(Uninitialized_Constructor) {}  // ironically, cannot be constexpr | 
|---|
| 75 |  | 
|---|
| 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 |  | 
|---|
| 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 |  | 
|---|
| 90 | constexpr SkMatrix44() : SkMatrix44{kIdentity_Constructor} {} | 
|---|
| 91 |  | 
|---|
| 92 | SkMatrix44(const SkMatrix44& src) = default; | 
|---|
| 93 |  | 
|---|
| 94 | SkMatrix44& operator=(const SkMatrix44& src) = default; | 
|---|
| 95 |  | 
|---|
| 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 | */ | 
|---|
| 143 | inline TypeMask getType() const { return fTypeMask; } | 
|---|
| 144 |  | 
|---|
| 145 | /** | 
|---|
| 146 | *  Return true if the matrix is identity. | 
|---|
| 147 | */ | 
|---|
| 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 | */ | 
|---|
| 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 | */ | 
|---|
| 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 | */ | 
|---|
| 169 | inline bool isScale() const { | 
|---|
| 170 | return !(this->getType() & ~kScale_Mask); | 
|---|
| 171 | } | 
|---|
| 172 |  | 
|---|
| 173 | inline bool hasPerspective() const { | 
|---|
| 174 | return SkToBool(this->getType() & kPerspective_Mask); | 
|---|
| 175 | } | 
|---|
| 176 |  | 
|---|
| 177 | void setIdentity(); | 
|---|
| 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 | */ | 
|---|
| 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 | */ | 
|---|
| 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 |  | 
|---|
| 205 | inline double getDouble(int row, int col) const { | 
|---|
| 206 | return double(this->get(row, col)); | 
|---|
| 207 | } | 
|---|
| 208 | inline void setDouble(int row, int col, double value) { | 
|---|
| 209 | this->set(row, col, SkScalar(value)); | 
|---|
| 210 | } | 
|---|
| 211 | inline float getFloat(int row, int col) const { | 
|---|
| 212 | return float(this->get(row, col)); | 
|---|
| 213 | } | 
|---|
| 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 |  | 
|---|
| 247 | void setColMajor(const SkScalar data[]) { this->setColMajorf(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 |  | 
|---|
| 271 | inline SkMatrix44& setScale(SkScalar scale) { | 
|---|
| 272 | return this->setScale(scale, scale, scale); | 
|---|
| 273 | } | 
|---|
| 274 | inline SkMatrix44& preScale(SkScalar scale) { | 
|---|
| 275 | return this->preScale(scale, scale, scale); | 
|---|
| 276 | } | 
|---|
| 277 | inline SkMatrix44& postScale(SkScalar scale) { | 
|---|
| 278 | return this->postScale(scale, scale, scale); | 
|---|
| 279 | } | 
|---|
| 280 |  | 
|---|
| 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); | 
|---|
| 295 | inline void preConcat(const SkMatrix44& m) { | 
|---|
| 296 | this->setConcat(*this, m); | 
|---|
| 297 | } | 
|---|
| 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; | 
|---|
| 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 |  | 
|---|
| 366 | SkScalar transX() const { return fMat[3][0]; } | 
|---|
| 367 | SkScalar transY() const { return fMat[3][1]; } | 
|---|
| 368 | SkScalar transZ() const { return fMat[3][2]; } | 
|---|
| 369 |  | 
|---|
| 370 | SkScalar scaleX() const { return fMat[0][0]; } | 
|---|
| 371 | SkScalar scaleY() const { return fMat[1][1]; } | 
|---|
| 372 | SkScalar scaleZ() const { return fMat[2][2]; } | 
|---|
| 373 |  | 
|---|
| 374 | SkScalar perspX() const { return fMat[0][3]; } | 
|---|
| 375 | SkScalar perspY() const { return fMat[1][3]; } | 
|---|
| 376 | SkScalar perspZ() const { return fMat[2][3]; } | 
|---|
| 377 |  | 
|---|
| 378 | void recomputeTypeMask(); | 
|---|
| 379 |  | 
|---|
| 380 | inline void setTypeMask(TypeMask mask) { | 
|---|
| 381 | SkASSERT(0 == (~kAllPublic_Masks & mask)); | 
|---|
| 382 | fTypeMask = mask; | 
|---|
| 383 | } | 
|---|
| 384 |  | 
|---|
| 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 |  | 
|---|