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 20 static inline double SkFloatToMScalar(float x) { 21 return static_cast<double>(x); 22 } 23 static inline float SkMScalarToFloat(double x) { 24 return static_cast<float>(x); 25 } 26 static inline double SkDoubleToMScalar(double x) { 27 return x; 28 } 29 static inline double SkMScalarToDouble(double x) { 30 return x; 31 } 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 52 static inline float SkFloatToMScalar(float x) { 53 return x; 54 } 55 static inline float SkMScalarToFloat(float x) { 56 return x; 57 } 58 static inline float SkDoubleToMScalar(double x) { 59 return static_cast<float>(x); 60 } 61 static inline double SkMScalarToDouble(float x) { 62 return static_cast<double>(x); 63 } 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 91 SkVector4() { 92 this->set(0, 0, 0, 1); 93 } 94 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 SK_API SkMatrix44 { 130 public: 131 132 enum Uninitialized_Constructor { 133 kUninitialized_Constructor 134 }; 135 enum Identity_Constructor { 136 kIdentity_Constructor 137 }; 138 139 SkMatrix44(Uninitialized_Constructor) { } 140 SkMatrix44(Identity_Constructor) { this->setIdentity(); } 141 142 SK_ATTR_DEPRECATED("use the constructors that take an enum") 143 SkMatrix44() { this->setIdentity(); } 144 145 SkMatrix44(const SkMatrix44& src) { 146 memcpy(fMat, src.fMat, sizeof(fMat)); 147 fTypeMask = src.fTypeMask; 148 } 149 150 SkMatrix44(const SkMatrix44& a, const SkMatrix44& b) { 151 this->setConcat(a, b); 152 } 153 154 SkMatrix44& operator=(const SkMatrix44& src) { 155 if (&src != this) { 156 memcpy(fMat, src.fMat, sizeof(fMat)); 157 fTypeMask = src.fTypeMask; 158 } 159 return *this; 160 } 161 162 bool operator==(const SkMatrix44& other) const; 163 bool operator!=(const SkMatrix44& other) const { 164 return !(other == *this); 165 } 166 167 /* When converting from SkMatrix44 to SkMatrix, the third row and 168 * column is dropped. When converting from SkMatrix to SkMatrix44 169 * the third row and column remain as identity: 170 * [ a b c ] [ a b 0 c ] 171 * [ d e f ] -> [ d e 0 f ] 172 * [ g h i ] [ 0 0 1 0 ] 173 * [ g h 0 i ] 174 */ 175 SkMatrix44(const SkMatrix&); 176 SkMatrix44& operator=(const SkMatrix& src); 177 operator SkMatrix() const; 178 179 /** 180 * Return a reference to a const identity matrix 181 */ 182 static const SkMatrix44& I(); 183 184 enum TypeMask { 185 kIdentity_Mask = 0, 186 kTranslate_Mask = 0x01, //!< set if the matrix has translation 187 kScale_Mask = 0x02, //!< set if the matrix has any scale != 1 188 kAffine_Mask = 0x04, //!< set if the matrix skews or rotates 189 kPerspective_Mask = 0x08 //!< set if the matrix is in perspective 190 }; 191 192 /** 193 * Returns a bitfield describing the transformations the matrix may 194 * perform. The bitfield is computed conservatively, so it may include 195 * false positives. For example, when kPerspective_Mask is true, all 196 * other bits may be set to true even in the case of a pure perspective 197 * transform. 198 */ 199 inline TypeMask getType() const { 200 if (fTypeMask & kUnknown_Mask) { 201 fTypeMask = this->computeTypeMask(); 202 } 203 SkASSERT(!(fTypeMask & kUnknown_Mask)); 204 return (TypeMask)fTypeMask; 205 } 206 207 /** 208 * Return true if the matrix is identity. 209 */ 210 inline bool isIdentity() const { 211 return kIdentity_Mask == this->getType(); 212 } 213 214 /** 215 * Return true if the matrix contains translate or is identity. 216 */ 217 inline bool isTranslate() const { 218 return !(this->getType() & ~kTranslate_Mask); 219 } 220 221 /** 222 * Return true if the matrix only contains scale or translate or is identity. 223 */ 224 inline bool isScaleTranslate() const { 225 return !(this->getType() & ~(kScale_Mask | kTranslate_Mask)); 226 } 227 228 /** 229 * Returns true if the matrix only contains scale or is identity. 230 */ 231 inline bool isScale() const { 232 return !(this->getType() & ~kScale_Mask); 233 } 234 235 inline bool hasPerspective() const { 236 return SkToBool(this->getType() & kPerspective_Mask); 237 } 238 239 void setIdentity(); 240 inline void reset() { this->setIdentity();} 241 242 /** 243 * get a value from the matrix. The row,col parameters work as follows: 244 * (0, 0) scale-x 245 * (0, 3) translate-x 246 * (3, 0) perspective-x 247 */ 248 inline SkMScalar get(int row, int col) const { 249 SkASSERT((unsigned)row <= 3); 250 SkASSERT((unsigned)col <= 3); 251 return fMat[col][row]; 252 } 253 254 /** 255 * set a value in the matrix. The row,col parameters work as follows: 256 * (0, 0) scale-x 257 * (0, 3) translate-x 258 * (3, 0) perspective-x 259 */ 260 inline void set(int row, int col, SkMScalar value) { 261 SkASSERT((unsigned)row <= 3); 262 SkASSERT((unsigned)col <= 3); 263 fMat[col][row] = value; 264 this->dirtyTypeMask(); 265 } 266 267 inline double getDouble(int row, int col) const { 268 return SkMScalarToDouble(this->get(row, col)); 269 } 270 inline void setDouble(int row, int col, double value) { 271 this->set(row, col, SkDoubleToMScalar(value)); 272 } 273 inline float getFloat(int row, int col) const { 274 return SkMScalarToFloat(this->get(row, col)); 275 } 276 inline void setFloat(int row, int col, float value) { 277 this->set(row, col, SkFloatToMScalar(value)); 278 } 279 280 /** These methods allow one to efficiently read matrix entries into an 281 * array. The given array must have room for exactly 16 entries. Whenever 282 * possible, they will try to use memcpy rather than an entry-by-entry 283 * copy. 284 */ 285 void asColMajorf(float[]) const; 286 void asColMajord(double[]) const; 287 void asRowMajorf(float[]) const; 288 void asRowMajord(double[]) const; 289 290 /** These methods allow one to efficiently set all matrix entries from an 291 * array. The given array must have room for exactly 16 entries. Whenever 292 * possible, they will try to use memcpy rather than an entry-by-entry 293 * copy. 294 */ 295 void setColMajorf(const float[]); 296 void setColMajord(const double[]); 297 void setRowMajorf(const float[]); 298 void setRowMajord(const double[]); 299 300 #ifdef SK_MSCALAR_IS_FLOAT 301 void setColMajor(const SkMScalar data[]) { this->setColMajorf(data); } 302 void setRowMajor(const SkMScalar data[]) { this->setRowMajorf(data); } 303 #else 304 void setColMajor(const SkMScalar data[]) { this->setColMajord(data); } 305 void setRowMajor(const SkMScalar data[]) { this->setRowMajord(data); } 306 #endif 307 308 /* This sets the top-left of the matrix and clears the translation and 309 * perspective components (with [3][3] set to 1). */ 310 void set3x3(SkMScalar m00, SkMScalar m01, SkMScalar m02, 311 SkMScalar m10, SkMScalar m11, SkMScalar m12, 312 SkMScalar m20, SkMScalar m21, SkMScalar m22); 313 314 void setTranslate(SkMScalar dx, SkMScalar dy, SkMScalar dz); 315 void preTranslate(SkMScalar dx, SkMScalar dy, SkMScalar dz); 316 void postTranslate(SkMScalar dx, SkMScalar dy, SkMScalar dz); 317 318 void setScale(SkMScalar sx, SkMScalar sy, SkMScalar sz); 319 void preScale(SkMScalar sx, SkMScalar sy, SkMScalar sz); 320 void postScale(SkMScalar sx, SkMScalar sy, SkMScalar sz); 321 322 inline void setScale(SkMScalar scale) { 323 this->setScale(scale, scale, scale); 324 } 325 inline void preScale(SkMScalar scale) { 326 this->preScale(scale, scale, scale); 327 } 328 inline void postScale(SkMScalar scale) { 329 this->postScale(scale, scale, scale); 330 } 331 332 void setRotateDegreesAbout(SkMScalar x, SkMScalar y, SkMScalar z, 333 SkMScalar degrees) { 334 this->setRotateAbout(x, y, z, degrees * SK_MScalarPI / 180); 335 } 336 337 /** Rotate about the vector [x,y,z]. If that vector is not unit-length, 338 it will be automatically resized. 339 */ 340 void setRotateAbout(SkMScalar x, SkMScalar y, SkMScalar z, 341 SkMScalar radians); 342 /** Rotate about the vector [x,y,z]. Does not check the length of the 343 vector, assuming it is unit-length. 344 */ 345 void setRotateAboutUnit(SkMScalar x, SkMScalar y, SkMScalar z, 346 SkMScalar radians); 347 348 void setConcat(const SkMatrix44& a, const SkMatrix44& b); 349 inline void preConcat(const SkMatrix44& m) { 350 this->setConcat(*this, m); 351 } 352 inline void postConcat(const SkMatrix44& m) { 353 this->setConcat(m, *this); 354 } 355 356 friend SkMatrix44 operator*(const SkMatrix44& a, const SkMatrix44& b) { 357 return SkMatrix44(a, b); 358 } 359 360 /** If this is invertible, return that in inverse and return true. If it is 361 not invertible, return false and leave the inverse parameter in an 362 unspecified state. 363 */ 364 bool invert(SkMatrix44* inverse) const; 365 366 /** Transpose this matrix in place. */ 367 void transpose(); 368 369 /** Apply the matrix to the src vector, returning the new vector in dst. 370 It is legal for src and dst to point to the same memory. 371 */ 372 void mapScalars(const SkScalar src[4], SkScalar dst[4]) const; 373 inline void mapScalars(SkScalar vec[4]) const { 374 this->mapScalars(vec, vec); 375 } 376 377 SK_ATTR_DEPRECATED("use mapScalars") 378 void map(const SkScalar src[4], SkScalar dst[4]) const { 379 this->mapScalars(src, dst); 380 } 381 382 SK_ATTR_DEPRECATED("use mapScalars") 383 void map(SkScalar vec[4]) const { 384 this->mapScalars(vec, vec); 385 } 386 387 #ifdef SK_MSCALAR_IS_DOUBLE 388 void mapMScalars(const SkMScalar src[4], SkMScalar dst[4]) const; 389 #elif defined SK_MSCALAR_IS_FLOAT 390 inline void mapMScalars(const SkMScalar src[4], SkMScalar dst[4]) const { 391 this->mapScalars(src, dst); 392 } 393 #endif 394 inline void mapMScalars(SkMScalar vec[4]) const { 395 this->mapMScalars(vec, vec); 396 } 397 398 friend SkVector4 operator*(const SkMatrix44& m, const SkVector4& src) { 399 SkVector4 dst; 400 m.mapScalars(src.fData, dst.fData); 401 return dst; 402 } 403 404 /** 405 * map an array of [x, y, 0, 1] through the matrix, returning an array 406 * of [x', y', z', w']. 407 * 408 * @param src2 array of [x, y] pairs, with implied z=0 and w=1 409 * @param count number of [x, y] pairs in src2 410 * @param dst4 array of [x', y', z', w'] quads as the output. 411 */ 412 void map2(const float src2[], int count, float dst4[]) const; 413 void map2(const double src2[], int count, double dst4[]) const; 414 415 /** Returns true if transformating an axis-aligned square in 2d by this matrix 416 will produce another 2d axis-aligned square; typically means the matrix 417 is a scale with perhaps a 90-degree rotation. A 3d rotation through 90 418 degrees into a perpendicular plane collapses a square to a line, but 419 is still considered to be axis-aligned. 420 421 By default, tolerates very slight error due to float imprecisions; 422 a 90-degree rotation can still end up with 10^-17 of 423 "non-axis-aligned" result. 424 */ 425 bool preserves2dAxisAlignment(SkMScalar epsilon = SK_ScalarNearlyZero) const; 426 427 void dump() const; 428 429 double determinant() const; 430 431 private: 432 SkMScalar fMat[4][4]; 433 mutable unsigned fTypeMask; 434 435 enum { 436 kUnknown_Mask = 0x80, 437 438 kAllPublic_Masks = 0xF 439 }; 440 441 SkMScalar transX() const { return fMat[3][0]; } 442 SkMScalar transY() const { return fMat[3][1]; } 443 SkMScalar transZ() const { return fMat[3][2]; } 444 445 SkMScalar scaleX() const { return fMat[0][0]; } 446 SkMScalar scaleY() const { return fMat[1][1]; } 447 SkMScalar scaleZ() const { return fMat[2][2]; } 448 449 SkMScalar perspX() const { return fMat[0][3]; } 450 SkMScalar perspY() const { return fMat[1][3]; } 451 SkMScalar perspZ() const { return fMat[2][3]; } 452 453 int computeTypeMask() const; 454 455 inline void dirtyTypeMask() { 456 fTypeMask = kUnknown_Mask; 457 } 458 459 inline void setTypeMask(int mask) { 460 SkASSERT(0 == (~(kAllPublic_Masks | kUnknown_Mask) & mask)); 461 fTypeMask = mask; 462 } 463 464 /** 465 * Does not take the time to 'compute' the typemask. Only returns true if 466 * we already know that this matrix is identity. 467 */ 468 inline bool isTriviallyIdentity() const { 469 return 0 == fTypeMask; 470 } 471 }; 472 473 #endif 474