1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/skia/trunk/include/utils/SkMatrix44.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,422 @@ 1.4 +/* 1.5 + * Copyright 2011 Google Inc. 1.6 + * 1.7 + * Use of this source code is governed by a BSD-style license that can be 1.8 + * found in the LICENSE file. 1.9 + */ 1.10 + 1.11 +#ifndef SkMatrix44_DEFINED 1.12 +#define SkMatrix44_DEFINED 1.13 + 1.14 +#include "SkMatrix.h" 1.15 +#include "SkScalar.h" 1.16 + 1.17 +#ifdef SK_MSCALAR_IS_DOUBLE 1.18 +#ifdef SK_MSCALAR_IS_FLOAT 1.19 + #error "can't define MSCALAR both as DOUBLE and FLOAT" 1.20 +#endif 1.21 + typedef double SkMScalar; 1.22 + 1.23 + static inline double SkFloatToMScalar(float x) { 1.24 + return static_cast<double>(x); 1.25 + } 1.26 + static inline float SkMScalarToFloat(double x) { 1.27 + return static_cast<float>(x); 1.28 + } 1.29 + static inline double SkDoubleToMScalar(double x) { 1.30 + return x; 1.31 + } 1.32 + static inline double SkMScalarToDouble(double x) { 1.33 + return x; 1.34 + } 1.35 + static const SkMScalar SK_MScalarPI = 3.141592653589793; 1.36 +#elif defined SK_MSCALAR_IS_FLOAT 1.37 +#ifdef SK_MSCALAR_IS_DOUBLE 1.38 + #error "can't define MSCALAR both as DOUBLE and FLOAT" 1.39 +#endif 1.40 + typedef float SkMScalar; 1.41 + 1.42 + static inline float SkFloatToMScalar(float x) { 1.43 + return x; 1.44 + } 1.45 + static inline float SkMScalarToFloat(float x) { 1.46 + return x; 1.47 + } 1.48 + static inline float SkDoubleToMScalar(double x) { 1.49 + return static_cast<float>(x); 1.50 + } 1.51 + static inline double SkMScalarToDouble(float x) { 1.52 + return static_cast<double>(x); 1.53 + } 1.54 + static const SkMScalar SK_MScalarPI = 3.14159265f; 1.55 +#endif 1.56 + 1.57 +#define SkMScalarToScalar SkMScalarToFloat 1.58 +#define SkScalarToMScalar SkFloatToMScalar 1.59 + 1.60 +static const SkMScalar SK_MScalar1 = 1; 1.61 + 1.62 +/////////////////////////////////////////////////////////////////////////////// 1.63 + 1.64 +struct SkVector4 { 1.65 + SkScalar fData[4]; 1.66 + 1.67 + SkVector4() { 1.68 + this->set(0, 0, 0, 1); 1.69 + } 1.70 + SkVector4(const SkVector4& src) { 1.71 + memcpy(fData, src.fData, sizeof(fData)); 1.72 + } 1.73 + SkVector4(SkScalar x, SkScalar y, SkScalar z, SkScalar w = SK_Scalar1) { 1.74 + fData[0] = x; 1.75 + fData[1] = y; 1.76 + fData[2] = z; 1.77 + fData[3] = w; 1.78 + } 1.79 + 1.80 + SkVector4& operator=(const SkVector4& src) { 1.81 + memcpy(fData, src.fData, sizeof(fData)); 1.82 + return *this; 1.83 + } 1.84 + 1.85 + bool operator==(const SkVector4& v) { 1.86 + return fData[0] == v.fData[0] && fData[1] == v.fData[1] && 1.87 + fData[2] == v.fData[2] && fData[3] == v.fData[3]; 1.88 + } 1.89 + bool operator!=(const SkVector4& v) { 1.90 + return !(*this == v); 1.91 + } 1.92 + bool equals(SkScalar x, SkScalar y, SkScalar z, SkScalar w = SK_Scalar1) { 1.93 + return fData[0] == x && fData[1] == y && 1.94 + fData[2] == z && fData[3] == w; 1.95 + } 1.96 + 1.97 + void set(SkScalar x, SkScalar y, SkScalar z, SkScalar w = SK_Scalar1) { 1.98 + fData[0] = x; 1.99 + fData[1] = y; 1.100 + fData[2] = z; 1.101 + fData[3] = w; 1.102 + } 1.103 +}; 1.104 + 1.105 +class SK_API SkMatrix44 { 1.106 +public: 1.107 + 1.108 + enum Uninitialized_Constructor { 1.109 + kUninitialized_Constructor 1.110 + }; 1.111 + enum Identity_Constructor { 1.112 + kIdentity_Constructor 1.113 + }; 1.114 + 1.115 + SkMatrix44(Uninitialized_Constructor) { } 1.116 + SkMatrix44(Identity_Constructor) { this->setIdentity(); } 1.117 + 1.118 + SK_ATTR_DEPRECATED("use the constructors that take an enum") 1.119 + SkMatrix44() { this->setIdentity(); } 1.120 + 1.121 + SkMatrix44(const SkMatrix44& src) { 1.122 + memcpy(fMat, src.fMat, sizeof(fMat)); 1.123 + fTypeMask = src.fTypeMask; 1.124 + } 1.125 + 1.126 + SkMatrix44(const SkMatrix44& a, const SkMatrix44& b) { 1.127 + this->setConcat(a, b); 1.128 + } 1.129 + 1.130 + SkMatrix44& operator=(const SkMatrix44& src) { 1.131 + if (&src != this) { 1.132 + memcpy(fMat, src.fMat, sizeof(fMat)); 1.133 + fTypeMask = src.fTypeMask; 1.134 + } 1.135 + return *this; 1.136 + } 1.137 + 1.138 + bool operator==(const SkMatrix44& other) const; 1.139 + bool operator!=(const SkMatrix44& other) const { 1.140 + return !(other == *this); 1.141 + } 1.142 + 1.143 + /* When converting from SkMatrix44 to SkMatrix, the third row and 1.144 + * column is dropped. When converting from SkMatrix to SkMatrix44 1.145 + * the third row and column remain as identity: 1.146 + * [ a b c ] [ a b 0 c ] 1.147 + * [ d e f ] -> [ d e 0 f ] 1.148 + * [ g h i ] [ 0 0 1 0 ] 1.149 + * [ g h 0 i ] 1.150 + */ 1.151 + SkMatrix44(const SkMatrix&); 1.152 + SkMatrix44& operator=(const SkMatrix& src); 1.153 + operator SkMatrix() const; 1.154 + 1.155 + /** 1.156 + * Return a reference to a const identity matrix 1.157 + */ 1.158 + static const SkMatrix44& I(); 1.159 + 1.160 + enum TypeMask { 1.161 + kIdentity_Mask = 0, 1.162 + kTranslate_Mask = 0x01, //!< set if the matrix has translation 1.163 + kScale_Mask = 0x02, //!< set if the matrix has any scale != 1 1.164 + kAffine_Mask = 0x04, //!< set if the matrix skews or rotates 1.165 + kPerspective_Mask = 0x08 //!< set if the matrix is in perspective 1.166 + }; 1.167 + 1.168 + /** 1.169 + * Returns a bitfield describing the transformations the matrix may 1.170 + * perform. The bitfield is computed conservatively, so it may include 1.171 + * false positives. For example, when kPerspective_Mask is true, all 1.172 + * other bits may be set to true even in the case of a pure perspective 1.173 + * transform. 1.174 + */ 1.175 + inline TypeMask getType() const { 1.176 + if (fTypeMask & kUnknown_Mask) { 1.177 + fTypeMask = this->computeTypeMask(); 1.178 + } 1.179 + SkASSERT(!(fTypeMask & kUnknown_Mask)); 1.180 + return (TypeMask)fTypeMask; 1.181 + } 1.182 + 1.183 + /** 1.184 + * Return true if the matrix is identity. 1.185 + */ 1.186 + inline bool isIdentity() const { 1.187 + return kIdentity_Mask == this->getType(); 1.188 + } 1.189 + 1.190 + /** 1.191 + * Return true if the matrix contains translate or is identity. 1.192 + */ 1.193 + inline bool isTranslate() const { 1.194 + return !(this->getType() & ~kTranslate_Mask); 1.195 + } 1.196 + 1.197 + /** 1.198 + * Return true if the matrix only contains scale or translate or is identity. 1.199 + */ 1.200 + inline bool isScaleTranslate() const { 1.201 + return !(this->getType() & ~(kScale_Mask | kTranslate_Mask)); 1.202 + } 1.203 + 1.204 + void setIdentity(); 1.205 + inline void reset() { this->setIdentity();} 1.206 + 1.207 + /** 1.208 + * get a value from the matrix. The row,col parameters work as follows: 1.209 + * (0, 0) scale-x 1.210 + * (0, 3) translate-x 1.211 + * (3, 0) perspective-x 1.212 + */ 1.213 + inline SkMScalar get(int row, int col) const { 1.214 + SkASSERT((unsigned)row <= 3); 1.215 + SkASSERT((unsigned)col <= 3); 1.216 + return fMat[col][row]; 1.217 + } 1.218 + 1.219 + /** 1.220 + * set a value in the matrix. The row,col parameters work as follows: 1.221 + * (0, 0) scale-x 1.222 + * (0, 3) translate-x 1.223 + * (3, 0) perspective-x 1.224 + */ 1.225 + inline void set(int row, int col, SkMScalar value) { 1.226 + SkASSERT((unsigned)row <= 3); 1.227 + SkASSERT((unsigned)col <= 3); 1.228 + fMat[col][row] = value; 1.229 + this->dirtyTypeMask(); 1.230 + } 1.231 + 1.232 + inline double getDouble(int row, int col) const { 1.233 + return SkMScalarToDouble(this->get(row, col)); 1.234 + } 1.235 + inline void setDouble(int row, int col, double value) { 1.236 + this->set(row, col, SkDoubleToMScalar(value)); 1.237 + } 1.238 + inline float getFloat(int row, int col) const { 1.239 + return SkMScalarToFloat(this->get(row, col)); 1.240 + } 1.241 + inline void setFloat(int row, int col, float value) { 1.242 + this->set(row, col, SkFloatToMScalar(value)); 1.243 + } 1.244 + 1.245 + /** These methods allow one to efficiently read matrix entries into an 1.246 + * array. The given array must have room for exactly 16 entries. Whenever 1.247 + * possible, they will try to use memcpy rather than an entry-by-entry 1.248 + * copy. 1.249 + */ 1.250 + void asColMajorf(float[]) const; 1.251 + void asColMajord(double[]) const; 1.252 + void asRowMajorf(float[]) const; 1.253 + void asRowMajord(double[]) const; 1.254 + 1.255 + /** These methods allow one to efficiently set all matrix entries from an 1.256 + * array. The given array must have room for exactly 16 entries. Whenever 1.257 + * possible, they will try to use memcpy rather than an entry-by-entry 1.258 + * copy. 1.259 + */ 1.260 + void setColMajorf(const float[]); 1.261 + void setColMajord(const double[]); 1.262 + void setRowMajorf(const float[]); 1.263 + void setRowMajord(const double[]); 1.264 + 1.265 +#ifdef SK_MSCALAR_IS_FLOAT 1.266 + void setColMajor(const SkMScalar data[]) { this->setColMajorf(data); } 1.267 + void setRowMajor(const SkMScalar data[]) { this->setRowMajorf(data); } 1.268 +#else 1.269 + void setColMajor(const SkMScalar data[]) { this->setColMajord(data); } 1.270 + void setRowMajor(const SkMScalar data[]) { this->setRowMajord(data); } 1.271 +#endif 1.272 + 1.273 + /* This sets the top-left of the matrix and clears the translation and 1.274 + * perspective components (with [3][3] set to 1). */ 1.275 + void set3x3(SkMScalar m00, SkMScalar m01, SkMScalar m02, 1.276 + SkMScalar m10, SkMScalar m11, SkMScalar m12, 1.277 + SkMScalar m20, SkMScalar m21, SkMScalar m22); 1.278 + 1.279 + void setTranslate(SkMScalar dx, SkMScalar dy, SkMScalar dz); 1.280 + void preTranslate(SkMScalar dx, SkMScalar dy, SkMScalar dz); 1.281 + void postTranslate(SkMScalar dx, SkMScalar dy, SkMScalar dz); 1.282 + 1.283 + void setScale(SkMScalar sx, SkMScalar sy, SkMScalar sz); 1.284 + void preScale(SkMScalar sx, SkMScalar sy, SkMScalar sz); 1.285 + void postScale(SkMScalar sx, SkMScalar sy, SkMScalar sz); 1.286 + 1.287 + inline void setScale(SkMScalar scale) { 1.288 + this->setScale(scale, scale, scale); 1.289 + } 1.290 + inline void preScale(SkMScalar scale) { 1.291 + this->preScale(scale, scale, scale); 1.292 + } 1.293 + inline void postScale(SkMScalar scale) { 1.294 + this->postScale(scale, scale, scale); 1.295 + } 1.296 + 1.297 + void setRotateDegreesAbout(SkMScalar x, SkMScalar y, SkMScalar z, 1.298 + SkMScalar degrees) { 1.299 + this->setRotateAbout(x, y, z, degrees * SK_MScalarPI / 180); 1.300 + } 1.301 + 1.302 + /** Rotate about the vector [x,y,z]. If that vector is not unit-length, 1.303 + it will be automatically resized. 1.304 + */ 1.305 + void setRotateAbout(SkMScalar x, SkMScalar y, SkMScalar z, 1.306 + SkMScalar radians); 1.307 + /** Rotate about the vector [x,y,z]. Does not check the length of the 1.308 + vector, assuming it is unit-length. 1.309 + */ 1.310 + void setRotateAboutUnit(SkMScalar x, SkMScalar y, SkMScalar z, 1.311 + SkMScalar radians); 1.312 + 1.313 + void setConcat(const SkMatrix44& a, const SkMatrix44& b); 1.314 + inline void preConcat(const SkMatrix44& m) { 1.315 + this->setConcat(*this, m); 1.316 + } 1.317 + inline void postConcat(const SkMatrix44& m) { 1.318 + this->setConcat(m, *this); 1.319 + } 1.320 + 1.321 + friend SkMatrix44 operator*(const SkMatrix44& a, const SkMatrix44& b) { 1.322 + return SkMatrix44(a, b); 1.323 + } 1.324 + 1.325 + /** If this is invertible, return that in inverse and return true. If it is 1.326 + not invertible, return false and ignore the inverse parameter. 1.327 + */ 1.328 + bool invert(SkMatrix44* inverse) const; 1.329 + 1.330 + /** Transpose this matrix in place. */ 1.331 + void transpose(); 1.332 + 1.333 + /** Apply the matrix to the src vector, returning the new vector in dst. 1.334 + It is legal for src and dst to point to the same memory. 1.335 + */ 1.336 + void mapScalars(const SkScalar src[4], SkScalar dst[4]) const; 1.337 + inline void mapScalars(SkScalar vec[4]) const { 1.338 + this->mapScalars(vec, vec); 1.339 + } 1.340 + 1.341 + SK_ATTR_DEPRECATED("use mapScalars") 1.342 + void map(const SkScalar src[4], SkScalar dst[4]) const { 1.343 + this->mapScalars(src, dst); 1.344 + } 1.345 + 1.346 + SK_ATTR_DEPRECATED("use mapScalars") 1.347 + void map(SkScalar vec[4]) const { 1.348 + this->mapScalars(vec, vec); 1.349 + } 1.350 + 1.351 +#ifdef SK_MSCALAR_IS_DOUBLE 1.352 + void mapMScalars(const SkMScalar src[4], SkMScalar dst[4]) const; 1.353 +#elif defined SK_MSCALAR_IS_FLOAT 1.354 + inline void mapMScalars(const SkMScalar src[4], SkMScalar dst[4]) const { 1.355 + this->mapScalars(src, dst); 1.356 + } 1.357 +#endif 1.358 + inline void mapMScalars(SkMScalar vec[4]) const { 1.359 + this->mapMScalars(vec, vec); 1.360 + } 1.361 + 1.362 + friend SkVector4 operator*(const SkMatrix44& m, const SkVector4& src) { 1.363 + SkVector4 dst; 1.364 + m.mapScalars(src.fData, dst.fData); 1.365 + return dst; 1.366 + } 1.367 + 1.368 + /** 1.369 + * map an array of [x, y, 0, 1] through the matrix, returning an array 1.370 + * of [x', y', z', w']. 1.371 + * 1.372 + * @param src2 array of [x, y] pairs, with implied z=0 and w=1 1.373 + * @param count number of [x, y] pairs in src2 1.374 + * @param dst4 array of [x', y', z', w'] quads as the output. 1.375 + */ 1.376 + void map2(const float src2[], int count, float dst4[]) const; 1.377 + void map2(const double src2[], int count, double dst4[]) const; 1.378 + 1.379 + void dump() const; 1.380 + 1.381 + double determinant() const; 1.382 + 1.383 +private: 1.384 + SkMScalar fMat[4][4]; 1.385 + mutable unsigned fTypeMask; 1.386 + 1.387 + enum { 1.388 + kUnknown_Mask = 0x80, 1.389 + 1.390 + kAllPublic_Masks = 0xF 1.391 + }; 1.392 + 1.393 + SkMScalar transX() const { return fMat[3][0]; } 1.394 + SkMScalar transY() const { return fMat[3][1]; } 1.395 + SkMScalar transZ() const { return fMat[3][2]; } 1.396 + 1.397 + SkMScalar scaleX() const { return fMat[0][0]; } 1.398 + SkMScalar scaleY() const { return fMat[1][1]; } 1.399 + SkMScalar scaleZ() const { return fMat[2][2]; } 1.400 + 1.401 + SkMScalar perspX() const { return fMat[0][3]; } 1.402 + SkMScalar perspY() const { return fMat[1][3]; } 1.403 + SkMScalar perspZ() const { return fMat[2][3]; } 1.404 + 1.405 + int computeTypeMask() const; 1.406 + 1.407 + inline void dirtyTypeMask() { 1.408 + fTypeMask = kUnknown_Mask; 1.409 + } 1.410 + 1.411 + inline void setTypeMask(int mask) { 1.412 + SkASSERT(0 == (~(kAllPublic_Masks | kUnknown_Mask) & mask)); 1.413 + fTypeMask = mask; 1.414 + } 1.415 + 1.416 + /** 1.417 + * Does not take the time to 'compute' the typemask. Only returns true if 1.418 + * we already know that this matrix is identity. 1.419 + */ 1.420 + inline bool isTriviallyIdentity() const { 1.421 + return 0 == fTypeMask; 1.422 + } 1.423 +}; 1.424 + 1.425 +#endif