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