1ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com/*
2ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Copyright 2011 Google Inc.
3ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com *
4ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Use of this source code is governed by a BSD-style license that can be
5ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * found in the LICENSE file.
68260a895869beaa4cab9f8b915e457728f41e561reed@google.com */
78260a895869beaa4cab9f8b915e457728f41e561reed@google.com
88260a895869beaa4cab9f8b915e457728f41e561reed@google.com#ifndef SkMatrix44_DEFINED
98260a895869beaa4cab9f8b915e457728f41e561reed@google.com#define SkMatrix44_DEFINED
108260a895869beaa4cab9f8b915e457728f41e561reed@google.com
118260a895869beaa4cab9f8b915e457728f41e561reed@google.com#include "SkMatrix.h"
128260a895869beaa4cab9f8b915e457728f41e561reed@google.com#include "SkScalar.h"
138260a895869beaa4cab9f8b915e457728f41e561reed@google.com
148260a895869beaa4cab9f8b915e457728f41e561reed@google.com#ifdef SK_MSCALAR_IS_DOUBLE
157d68335eb427547606497eb4edea81acce7891f9reed@google.com#ifdef SK_MSCALAR_IS_FLOAT
167d68335eb427547606497eb4edea81acce7891f9reed@google.com    #error "can't define MSCALAR both as DOUBLE and FLOAT"
177d68335eb427547606497eb4edea81acce7891f9reed@google.com#endif
188260a895869beaa4cab9f8b915e457728f41e561reed@google.com    typedef double SkMScalar;
197d68335eb427547606497eb4edea81acce7891f9reed@google.com
208260a895869beaa4cab9f8b915e457728f41e561reed@google.com    static inline double SkFloatToMScalar(float x) {
218260a895869beaa4cab9f8b915e457728f41e561reed@google.com        return static_cast<double>(x);
228260a895869beaa4cab9f8b915e457728f41e561reed@google.com    }
238260a895869beaa4cab9f8b915e457728f41e561reed@google.com    static inline float SkMScalarToFloat(double x) {
248260a895869beaa4cab9f8b915e457728f41e561reed@google.com        return static_cast<float>(x);
258260a895869beaa4cab9f8b915e457728f41e561reed@google.com    }
268260a895869beaa4cab9f8b915e457728f41e561reed@google.com    static inline double SkDoubleToMScalar(double x) {
278260a895869beaa4cab9f8b915e457728f41e561reed@google.com        return x;
288260a895869beaa4cab9f8b915e457728f41e561reed@google.com    }
298260a895869beaa4cab9f8b915e457728f41e561reed@google.com    static inline double SkMScalarToDouble(double x) {
308260a895869beaa4cab9f8b915e457728f41e561reed@google.com        return x;
318260a895869beaa4cab9f8b915e457728f41e561reed@google.com    }
328260a895869beaa4cab9f8b915e457728f41e561reed@google.com    static const SkMScalar SK_MScalarPI = 3.141592653589793;
335596a69e9f7884e3042bceba071c468dee52aa7fvollick@chromium.org#elif defined SK_MSCALAR_IS_FLOAT
347d68335eb427547606497eb4edea81acce7891f9reed@google.com#ifdef SK_MSCALAR_IS_DOUBLE
357d68335eb427547606497eb4edea81acce7891f9reed@google.com    #error "can't define MSCALAR both as DOUBLE and FLOAT"
367d68335eb427547606497eb4edea81acce7891f9reed@google.com#endif
378260a895869beaa4cab9f8b915e457728f41e561reed@google.com    typedef float SkMScalar;
380264fb4543b0d8cebe00f1ee32433784f4ceb074skia.committer@gmail.com
398260a895869beaa4cab9f8b915e457728f41e561reed@google.com    static inline float SkFloatToMScalar(float x) {
408260a895869beaa4cab9f8b915e457728f41e561reed@google.com        return x;
418260a895869beaa4cab9f8b915e457728f41e561reed@google.com    }
428260a895869beaa4cab9f8b915e457728f41e561reed@google.com    static inline float SkMScalarToFloat(float x) {
438260a895869beaa4cab9f8b915e457728f41e561reed@google.com        return x;
448260a895869beaa4cab9f8b915e457728f41e561reed@google.com    }
458260a895869beaa4cab9f8b915e457728f41e561reed@google.com    static inline float SkDoubleToMScalar(double x) {
468260a895869beaa4cab9f8b915e457728f41e561reed@google.com        return static_cast<float>(x);
478260a895869beaa4cab9f8b915e457728f41e561reed@google.com    }
488260a895869beaa4cab9f8b915e457728f41e561reed@google.com    static inline double SkMScalarToDouble(float x) {
498260a895869beaa4cab9f8b915e457728f41e561reed@google.com        return static_cast<double>(x);
508260a895869beaa4cab9f8b915e457728f41e561reed@google.com    }
518260a895869beaa4cab9f8b915e457728f41e561reed@google.com    static const SkMScalar SK_MScalarPI = 3.14159265f;
528260a895869beaa4cab9f8b915e457728f41e561reed@google.com#endif
538260a895869beaa4cab9f8b915e457728f41e561reed@google.com
5420d44677a1940c17ae9c64420b013d76bf895dd5reed@google.com#define SkMScalarToScalar SkMScalarToFloat
5520d44677a1940c17ae9c64420b013d76bf895dd5reed@google.com#define SkScalarToMScalar SkFloatToMScalar
5672e49b8982586a5d8b0425f16d909c05a36ea8c3bsalomon@google.com
578260a895869beaa4cab9f8b915e457728f41e561reed@google.comstatic const SkMScalar SK_MScalar1 = 1;
588260a895869beaa4cab9f8b915e457728f41e561reed@google.com
598260a895869beaa4cab9f8b915e457728f41e561reed@google.com///////////////////////////////////////////////////////////////////////////////
608260a895869beaa4cab9f8b915e457728f41e561reed@google.com
618260a895869beaa4cab9f8b915e457728f41e561reed@google.comstruct SkVector4 {
628260a895869beaa4cab9f8b915e457728f41e561reed@google.com    SkScalar fData[4];
638260a895869beaa4cab9f8b915e457728f41e561reed@google.com
648260a895869beaa4cab9f8b915e457728f41e561reed@google.com    SkVector4() {
658260a895869beaa4cab9f8b915e457728f41e561reed@google.com        this->set(0, 0, 0, 1);
668260a895869beaa4cab9f8b915e457728f41e561reed@google.com    }
678260a895869beaa4cab9f8b915e457728f41e561reed@google.com    SkVector4(const SkVector4& src) {
688260a895869beaa4cab9f8b915e457728f41e561reed@google.com        memcpy(fData, src.fData, sizeof(fData));
698260a895869beaa4cab9f8b915e457728f41e561reed@google.com    }
708260a895869beaa4cab9f8b915e457728f41e561reed@google.com    SkVector4(SkScalar x, SkScalar y, SkScalar z, SkScalar w = SK_Scalar1) {
718260a895869beaa4cab9f8b915e457728f41e561reed@google.com        fData[0] = x;
728260a895869beaa4cab9f8b915e457728f41e561reed@google.com        fData[1] = y;
738260a895869beaa4cab9f8b915e457728f41e561reed@google.com        fData[2] = z;
748260a895869beaa4cab9f8b915e457728f41e561reed@google.com        fData[3] = w;
758260a895869beaa4cab9f8b915e457728f41e561reed@google.com    }
768260a895869beaa4cab9f8b915e457728f41e561reed@google.com
778260a895869beaa4cab9f8b915e457728f41e561reed@google.com    SkVector4& operator=(const SkVector4& src) {
788260a895869beaa4cab9f8b915e457728f41e561reed@google.com        memcpy(fData, src.fData, sizeof(fData));
798260a895869beaa4cab9f8b915e457728f41e561reed@google.com        return *this;
808260a895869beaa4cab9f8b915e457728f41e561reed@google.com    }
818260a895869beaa4cab9f8b915e457728f41e561reed@google.com
828260a895869beaa4cab9f8b915e457728f41e561reed@google.com    bool operator==(const SkVector4& v) {
838260a895869beaa4cab9f8b915e457728f41e561reed@google.com        return fData[0] == v.fData[0] && fData[1] == v.fData[1] &&
848260a895869beaa4cab9f8b915e457728f41e561reed@google.com               fData[2] == v.fData[2] && fData[3] == v.fData[3];
858260a895869beaa4cab9f8b915e457728f41e561reed@google.com    }
868260a895869beaa4cab9f8b915e457728f41e561reed@google.com    bool operator!=(const SkVector4& v) {
878260a895869beaa4cab9f8b915e457728f41e561reed@google.com        return !(*this == v);
888260a895869beaa4cab9f8b915e457728f41e561reed@google.com    }
898260a895869beaa4cab9f8b915e457728f41e561reed@google.com    bool equals(SkScalar x, SkScalar y, SkScalar z, SkScalar w = SK_Scalar1) {
908260a895869beaa4cab9f8b915e457728f41e561reed@google.com        return fData[0] == x && fData[1] == y &&
918260a895869beaa4cab9f8b915e457728f41e561reed@google.com               fData[2] == z && fData[3] == w;
928260a895869beaa4cab9f8b915e457728f41e561reed@google.com    }
938260a895869beaa4cab9f8b915e457728f41e561reed@google.com
948260a895869beaa4cab9f8b915e457728f41e561reed@google.com    void set(SkScalar x, SkScalar y, SkScalar z, SkScalar w = SK_Scalar1) {
958260a895869beaa4cab9f8b915e457728f41e561reed@google.com        fData[0] = x;
968260a895869beaa4cab9f8b915e457728f41e561reed@google.com        fData[1] = y;
978260a895869beaa4cab9f8b915e457728f41e561reed@google.com        fData[2] = z;
988260a895869beaa4cab9f8b915e457728f41e561reed@google.com        fData[3] = w;
998260a895869beaa4cab9f8b915e457728f41e561reed@google.com    }
1008260a895869beaa4cab9f8b915e457728f41e561reed@google.com};
1018260a895869beaa4cab9f8b915e457728f41e561reed@google.com
1027cfb9c7b6186bf1e42b7d13466eab94470587e7etomhudson@google.comclass SK_API SkMatrix44 {
1038260a895869beaa4cab9f8b915e457728f41e561reed@google.compublic:
10457a54e33cfe771c792b1086ba67484cb95938d5dvollick@chromium.org
10557a54e33cfe771c792b1086ba67484cb95938d5dvollick@chromium.org    enum Uninitialized_Constructor {
10657a54e33cfe771c792b1086ba67484cb95938d5dvollick@chromium.org        kUninitialized_Constructor
10757a54e33cfe771c792b1086ba67484cb95938d5dvollick@chromium.org    };
10857a54e33cfe771c792b1086ba67484cb95938d5dvollick@chromium.org    enum Identity_Constructor {
10957a54e33cfe771c792b1086ba67484cb95938d5dvollick@chromium.org        kIdentity_Constructor
11057a54e33cfe771c792b1086ba67484cb95938d5dvollick@chromium.org    };
11157a54e33cfe771c792b1086ba67484cb95938d5dvollick@chromium.org
11257a54e33cfe771c792b1086ba67484cb95938d5dvollick@chromium.org    SkMatrix44(Uninitialized_Constructor) { }
11357a54e33cfe771c792b1086ba67484cb95938d5dvollick@chromium.org    SkMatrix44(Identity_Constructor) { this->setIdentity(); }
11457a54e33cfe771c792b1086ba67484cb95938d5dvollick@chromium.org
1154469938e92d779dff05e745559e67907bbf21e78reed@google.com    SK_ATTR_DEPRECATED("use the constructors that take an enum")
1167d68335eb427547606497eb4edea81acce7891f9reed@google.com    SkMatrix44() { this->setIdentity(); }
117d53025364a8062b5c72f3f9ed54a613a1ae17958reed@google.com
118d53025364a8062b5c72f3f9ed54a613a1ae17958reed@google.com    SkMatrix44(const SkMatrix44& src) {
119d53025364a8062b5c72f3f9ed54a613a1ae17958reed@google.com        memcpy(fMat, src.fMat, sizeof(fMat));
120d53025364a8062b5c72f3f9ed54a613a1ae17958reed@google.com        fTypeMask = src.fTypeMask;
121d53025364a8062b5c72f3f9ed54a613a1ae17958reed@google.com    }
122d53025364a8062b5c72f3f9ed54a613a1ae17958reed@google.com
123d53025364a8062b5c72f3f9ed54a613a1ae17958reed@google.com    SkMatrix44(const SkMatrix44& a, const SkMatrix44& b) {
124d53025364a8062b5c72f3f9ed54a613a1ae17958reed@google.com        this->setConcat(a, b);
125d53025364a8062b5c72f3f9ed54a613a1ae17958reed@google.com    }
1268260a895869beaa4cab9f8b915e457728f41e561reed@google.com
1278260a895869beaa4cab9f8b915e457728f41e561reed@google.com    SkMatrix44& operator=(const SkMatrix44& src) {
1283fda0eadac18dc3071e2bb2979512bd580b39eadreed@google.com        if (&src != this) {
1293fda0eadac18dc3071e2bb2979512bd580b39eadreed@google.com            memcpy(fMat, src.fMat, sizeof(fMat));
1303fda0eadac18dc3071e2bb2979512bd580b39eadreed@google.com            fTypeMask = src.fTypeMask;
1313fda0eadac18dc3071e2bb2979512bd580b39eadreed@google.com        }
1328260a895869beaa4cab9f8b915e457728f41e561reed@google.com        return *this;
1338260a895869beaa4cab9f8b915e457728f41e561reed@google.com    }
1348260a895869beaa4cab9f8b915e457728f41e561reed@google.com
135631940c8c44e92939fc95d305b87be64eb9b886ereed@google.com    bool operator==(const SkMatrix44& other) const;
1368260a895869beaa4cab9f8b915e457728f41e561reed@google.com    bool operator!=(const SkMatrix44& other) const {
137631940c8c44e92939fc95d305b87be64eb9b886ereed@google.com        return !(other == *this);
1388260a895869beaa4cab9f8b915e457728f41e561reed@google.com    }
1398260a895869beaa4cab9f8b915e457728f41e561reed@google.com
140722555bebbe9128783b8dbe0e897c09c9ccb88cecommit-bot@chromium.org    /* When converting from SkMatrix44 to SkMatrix, the third row and
141722555bebbe9128783b8dbe0e897c09c9ccb88cecommit-bot@chromium.org     * column is dropped.  When converting from SkMatrix to SkMatrix44
142722555bebbe9128783b8dbe0e897c09c9ccb88cecommit-bot@chromium.org     * the third row and column remain as identity:
143722555bebbe9128783b8dbe0e897c09c9ccb88cecommit-bot@chromium.org     * [ a b c ]      [ a b 0 c ]
144722555bebbe9128783b8dbe0e897c09c9ccb88cecommit-bot@chromium.org     * [ d e f ]  ->  [ d e 0 f ]
145722555bebbe9128783b8dbe0e897c09c9ccb88cecommit-bot@chromium.org     * [ g h i ]      [ 0 0 1 0 ]
146722555bebbe9128783b8dbe0e897c09c9ccb88cecommit-bot@chromium.org     *                [ g h 0 i ]
147722555bebbe9128783b8dbe0e897c09c9ccb88cecommit-bot@chromium.org     */
1488260a895869beaa4cab9f8b915e457728f41e561reed@google.com    SkMatrix44(const SkMatrix&);
1498260a895869beaa4cab9f8b915e457728f41e561reed@google.com    SkMatrix44& operator=(const SkMatrix& src);
1508260a895869beaa4cab9f8b915e457728f41e561reed@google.com    operator SkMatrix() const;
1518260a895869beaa4cab9f8b915e457728f41e561reed@google.com
1527d68335eb427547606497eb4edea81acce7891f9reed@google.com    /**
1537d68335eb427547606497eb4edea81acce7891f9reed@google.com     *  Return a reference to a const identity matrix
1547d68335eb427547606497eb4edea81acce7891f9reed@google.com     */
1557d68335eb427547606497eb4edea81acce7891f9reed@google.com    static const SkMatrix44& I();
1567d68335eb427547606497eb4edea81acce7891f9reed@google.com
1577d68335eb427547606497eb4edea81acce7891f9reed@google.com    enum TypeMask {
1587d68335eb427547606497eb4edea81acce7891f9reed@google.com        kIdentity_Mask      = 0,
1597d68335eb427547606497eb4edea81acce7891f9reed@google.com        kTranslate_Mask     = 0x01,  //!< set if the matrix has translation
1607d68335eb427547606497eb4edea81acce7891f9reed@google.com        kScale_Mask         = 0x02,  //!< set if the matrix has any scale != 1
1617d68335eb427547606497eb4edea81acce7891f9reed@google.com        kAffine_Mask        = 0x04,  //!< set if the matrix skews or rotates
1627d68335eb427547606497eb4edea81acce7891f9reed@google.com        kPerspective_Mask   = 0x08   //!< set if the matrix is in perspective
1637d68335eb427547606497eb4edea81acce7891f9reed@google.com    };
1640264fb4543b0d8cebe00f1ee32433784f4ceb074skia.committer@gmail.com
1657d68335eb427547606497eb4edea81acce7891f9reed@google.com    /**
1667d68335eb427547606497eb4edea81acce7891f9reed@google.com     *  Returns a bitfield describing the transformations the matrix may
1677d68335eb427547606497eb4edea81acce7891f9reed@google.com     *  perform. The bitfield is computed conservatively, so it may include
1687d68335eb427547606497eb4edea81acce7891f9reed@google.com     *  false positives. For example, when kPerspective_Mask is true, all
1697d68335eb427547606497eb4edea81acce7891f9reed@google.com     *  other bits may be set to true even in the case of a pure perspective
1707d68335eb427547606497eb4edea81acce7891f9reed@google.com     *  transform.
1717d68335eb427547606497eb4edea81acce7891f9reed@google.com     */
1727d68335eb427547606497eb4edea81acce7891f9reed@google.com    inline TypeMask getType() const {
1737d68335eb427547606497eb4edea81acce7891f9reed@google.com        if (fTypeMask & kUnknown_Mask) {
1747d68335eb427547606497eb4edea81acce7891f9reed@google.com            fTypeMask = this->computeTypeMask();
1757d68335eb427547606497eb4edea81acce7891f9reed@google.com        }
1767d68335eb427547606497eb4edea81acce7891f9reed@google.com        SkASSERT(!(fTypeMask & kUnknown_Mask));
1777d68335eb427547606497eb4edea81acce7891f9reed@google.com        return (TypeMask)fTypeMask;
1787d68335eb427547606497eb4edea81acce7891f9reed@google.com    }
1797d68335eb427547606497eb4edea81acce7891f9reed@google.com
180f8b1ebc35b6872c2805a22481b7c23b85486fb46mike@reedtribe.org    /**
181f8b1ebc35b6872c2805a22481b7c23b85486fb46mike@reedtribe.org     *  Return true if the matrix is identity.
182f8b1ebc35b6872c2805a22481b7c23b85486fb46mike@reedtribe.org     */
1837d68335eb427547606497eb4edea81acce7891f9reed@google.com    inline bool isIdentity() const {
184f8b1ebc35b6872c2805a22481b7c23b85486fb46mike@reedtribe.org        return kIdentity_Mask == this->getType();
185f8b1ebc35b6872c2805a22481b7c23b85486fb46mike@reedtribe.org    }
186f8b1ebc35b6872c2805a22481b7c23b85486fb46mike@reedtribe.org
187f8b1ebc35b6872c2805a22481b7c23b85486fb46mike@reedtribe.org    /**
188f8b1ebc35b6872c2805a22481b7c23b85486fb46mike@reedtribe.org     *  Return true if the matrix contains translate or is identity.
189f8b1ebc35b6872c2805a22481b7c23b85486fb46mike@reedtribe.org     */
190f8b1ebc35b6872c2805a22481b7c23b85486fb46mike@reedtribe.org    inline bool isTranslate() const {
191f8b1ebc35b6872c2805a22481b7c23b85486fb46mike@reedtribe.org        return !(this->getType() & ~kTranslate_Mask);
192f8b1ebc35b6872c2805a22481b7c23b85486fb46mike@reedtribe.org    }
193f8b1ebc35b6872c2805a22481b7c23b85486fb46mike@reedtribe.org
194f8b1ebc35b6872c2805a22481b7c23b85486fb46mike@reedtribe.org    /**
195f8b1ebc35b6872c2805a22481b7c23b85486fb46mike@reedtribe.org     *  Return true if the matrix only contains scale or translate or is identity.
196f8b1ebc35b6872c2805a22481b7c23b85486fb46mike@reedtribe.org     */
197f8b1ebc35b6872c2805a22481b7c23b85486fb46mike@reedtribe.org    inline bool isScaleTranslate() const {
198f8b1ebc35b6872c2805a22481b7c23b85486fb46mike@reedtribe.org        return !(this->getType() & ~(kScale_Mask | kTranslate_Mask));
1997d68335eb427547606497eb4edea81acce7891f9reed@google.com    }
2000264fb4543b0d8cebe00f1ee32433784f4ceb074skia.committer@gmail.com
201a32f1758b7ebd889eecfdc67c935e7edcedc5be3tomhudson    inline bool hasPerspective() const {
202a32f1758b7ebd889eecfdc67c935e7edcedc5be3tomhudson        return SkToBool(this->getType() & kPerspective_Mask);
203a32f1758b7ebd889eecfdc67c935e7edcedc5be3tomhudson    }
204a32f1758b7ebd889eecfdc67c935e7edcedc5be3tomhudson
2057d68335eb427547606497eb4edea81acce7891f9reed@google.com    void setIdentity();
2067d68335eb427547606497eb4edea81acce7891f9reed@google.com    inline void reset() { this->setIdentity();}
2077d68335eb427547606497eb4edea81acce7891f9reed@google.com
2087d68335eb427547606497eb4edea81acce7891f9reed@google.com    /**
2097d68335eb427547606497eb4edea81acce7891f9reed@google.com     *  get a value from the matrix. The row,col parameters work as follows:
2107d68335eb427547606497eb4edea81acce7891f9reed@google.com     *  (0, 0)  scale-x
2117d68335eb427547606497eb4edea81acce7891f9reed@google.com     *  (0, 3)  translate-x
2127d68335eb427547606497eb4edea81acce7891f9reed@google.com     *  (3, 0)  perspective-x
2137d68335eb427547606497eb4edea81acce7891f9reed@google.com     */
2147d68335eb427547606497eb4edea81acce7891f9reed@google.com    inline SkMScalar get(int row, int col) const {
215631940c8c44e92939fc95d305b87be64eb9b886ereed@google.com        SkASSERT((unsigned)row <= 3);
216631940c8c44e92939fc95d305b87be64eb9b886ereed@google.com        SkASSERT((unsigned)col <= 3);
217631940c8c44e92939fc95d305b87be64eb9b886ereed@google.com        return fMat[col][row];
218631940c8c44e92939fc95d305b87be64eb9b886ereed@google.com    }
2198260a895869beaa4cab9f8b915e457728f41e561reed@google.com
2207d68335eb427547606497eb4edea81acce7891f9reed@google.com    /**
2217d68335eb427547606497eb4edea81acce7891f9reed@google.com     *  set a value in the matrix. The row,col parameters work as follows:
2227d68335eb427547606497eb4edea81acce7891f9reed@google.com     *  (0, 0)  scale-x
2237d68335eb427547606497eb4edea81acce7891f9reed@google.com     *  (0, 3)  translate-x
2247d68335eb427547606497eb4edea81acce7891f9reed@google.com     *  (3, 0)  perspective-x
2257d68335eb427547606497eb4edea81acce7891f9reed@google.com     */
2267d68335eb427547606497eb4edea81acce7891f9reed@google.com    inline void set(int row, int col, SkMScalar value) {
227631940c8c44e92939fc95d305b87be64eb9b886ereed@google.com        SkASSERT((unsigned)row <= 3);
228631940c8c44e92939fc95d305b87be64eb9b886ereed@google.com        SkASSERT((unsigned)col <= 3);
229631940c8c44e92939fc95d305b87be64eb9b886ereed@google.com        fMat[col][row] = value;
2307d68335eb427547606497eb4edea81acce7891f9reed@google.com        this->dirtyTypeMask();
231631940c8c44e92939fc95d305b87be64eb9b886ereed@google.com    }
232ab38f7acb336c4330af015312e854e990babd3f5skia.committer@gmail.com
2337d68335eb427547606497eb4edea81acce7891f9reed@google.com    inline double getDouble(int row, int col) const {
2349b21c25e742d6a8b69bee8b049e79877f93b5936vollick@chromium.org        return SkMScalarToDouble(this->get(row, col));
2359b21c25e742d6a8b69bee8b049e79877f93b5936vollick@chromium.org    }
2367d68335eb427547606497eb4edea81acce7891f9reed@google.com    inline void setDouble(int row, int col, double value) {
2379b21c25e742d6a8b69bee8b049e79877f93b5936vollick@chromium.org        this->set(row, col, SkDoubleToMScalar(value));
2389b21c25e742d6a8b69bee8b049e79877f93b5936vollick@chromium.org    }
239e2419cc5edbe1a6a7dae81a90ca44673a1fa030fcommit-bot@chromium.org    inline float getFloat(int row, int col) const {
240e2419cc5edbe1a6a7dae81a90ca44673a1fa030fcommit-bot@chromium.org        return SkMScalarToFloat(this->get(row, col));
241e2419cc5edbe1a6a7dae81a90ca44673a1fa030fcommit-bot@chromium.org    }
242e2419cc5edbe1a6a7dae81a90ca44673a1fa030fcommit-bot@chromium.org    inline void setFloat(int row, int col, float value) {
243e2419cc5edbe1a6a7dae81a90ca44673a1fa030fcommit-bot@chromium.org        this->set(row, col, SkFloatToMScalar(value));
244e2419cc5edbe1a6a7dae81a90ca44673a1fa030fcommit-bot@chromium.org    }
2459b21c25e742d6a8b69bee8b049e79877f93b5936vollick@chromium.org
246f11cf9ff885c81e29f55283174ca34ce2fc5fd23vollick@chromium.org    /** These methods allow one to efficiently read matrix entries into an
247f11cf9ff885c81e29f55283174ca34ce2fc5fd23vollick@chromium.org     *  array. The given array must have room for exactly 16 entries. Whenever
248f11cf9ff885c81e29f55283174ca34ce2fc5fd23vollick@chromium.org     *  possible, they will try to use memcpy rather than an entry-by-entry
249f11cf9ff885c81e29f55283174ca34ce2fc5fd23vollick@chromium.org     *  copy.
250f11cf9ff885c81e29f55283174ca34ce2fc5fd23vollick@chromium.org     */
251da9fac0aa13d1445f8b58a75d9390638845c814dreed@google.com    void asColMajorf(float[]) const;
252da9fac0aa13d1445f8b58a75d9390638845c814dreed@google.com    void asColMajord(double[]) const;
253da9fac0aa13d1445f8b58a75d9390638845c814dreed@google.com    void asRowMajorf(float[]) const;
254da9fac0aa13d1445f8b58a75d9390638845c814dreed@google.com    void asRowMajord(double[]) const;
255da9fac0aa13d1445f8b58a75d9390638845c814dreed@google.com
256f11cf9ff885c81e29f55283174ca34ce2fc5fd23vollick@chromium.org    /** These methods allow one to efficiently set all matrix entries from an
257f11cf9ff885c81e29f55283174ca34ce2fc5fd23vollick@chromium.org     *  array. The given array must have room for exactly 16 entries. Whenever
258f11cf9ff885c81e29f55283174ca34ce2fc5fd23vollick@chromium.org     *  possible, they will try to use memcpy rather than an entry-by-entry
259f11cf9ff885c81e29f55283174ca34ce2fc5fd23vollick@chromium.org     *  copy.
260f11cf9ff885c81e29f55283174ca34ce2fc5fd23vollick@chromium.org     */
261f11cf9ff885c81e29f55283174ca34ce2fc5fd23vollick@chromium.org    void setColMajorf(const float[]);
262f11cf9ff885c81e29f55283174ca34ce2fc5fd23vollick@chromium.org    void setColMajord(const double[]);
263f11cf9ff885c81e29f55283174ca34ce2fc5fd23vollick@chromium.org    void setRowMajorf(const float[]);
264f11cf9ff885c81e29f55283174ca34ce2fc5fd23vollick@chromium.org    void setRowMajord(const double[]);
265f11cf9ff885c81e29f55283174ca34ce2fc5fd23vollick@chromium.org
2667d68335eb427547606497eb4edea81acce7891f9reed@google.com#ifdef SK_MSCALAR_IS_FLOAT
2677d68335eb427547606497eb4edea81acce7891f9reed@google.com    void setColMajor(const SkMScalar data[]) { this->setColMajorf(data); }
2687d68335eb427547606497eb4edea81acce7891f9reed@google.com    void setRowMajor(const SkMScalar data[]) { this->setRowMajorf(data); }
2697d68335eb427547606497eb4edea81acce7891f9reed@google.com#else
2707d68335eb427547606497eb4edea81acce7891f9reed@google.com    void setColMajor(const SkMScalar data[]) { this->setColMajord(data); }
2717d68335eb427547606497eb4edea81acce7891f9reed@google.com    void setRowMajor(const SkMScalar data[]) { this->setRowMajord(data); }
2727d68335eb427547606497eb4edea81acce7891f9reed@google.com#endif
2738260a895869beaa4cab9f8b915e457728f41e561reed@google.com
274722555bebbe9128783b8dbe0e897c09c9ccb88cecommit-bot@chromium.org    /* This sets the top-left of the matrix and clears the translation and
275722555bebbe9128783b8dbe0e897c09c9ccb88cecommit-bot@chromium.org     * perspective components (with [3][3] set to 1). */
2768260a895869beaa4cab9f8b915e457728f41e561reed@google.com    void set3x3(SkMScalar m00, SkMScalar m01, SkMScalar m02,
2778260a895869beaa4cab9f8b915e457728f41e561reed@google.com                SkMScalar m10, SkMScalar m11, SkMScalar m12,
2788260a895869beaa4cab9f8b915e457728f41e561reed@google.com                SkMScalar m20, SkMScalar m21, SkMScalar m22);
2798260a895869beaa4cab9f8b915e457728f41e561reed@google.com
2808260a895869beaa4cab9f8b915e457728f41e561reed@google.com    void setTranslate(SkMScalar dx, SkMScalar dy, SkMScalar dz);
2818260a895869beaa4cab9f8b915e457728f41e561reed@google.com    void preTranslate(SkMScalar dx, SkMScalar dy, SkMScalar dz);
2828260a895869beaa4cab9f8b915e457728f41e561reed@google.com    void postTranslate(SkMScalar dx, SkMScalar dy, SkMScalar dz);
2838260a895869beaa4cab9f8b915e457728f41e561reed@google.com
2848260a895869beaa4cab9f8b915e457728f41e561reed@google.com    void setScale(SkMScalar sx, SkMScalar sy, SkMScalar sz);
2858260a895869beaa4cab9f8b915e457728f41e561reed@google.com    void preScale(SkMScalar sx, SkMScalar sy, SkMScalar sz);
2868260a895869beaa4cab9f8b915e457728f41e561reed@google.com    void postScale(SkMScalar sx, SkMScalar sy, SkMScalar sz);
2878260a895869beaa4cab9f8b915e457728f41e561reed@google.com
2887d68335eb427547606497eb4edea81acce7891f9reed@google.com    inline void setScale(SkMScalar scale) {
2898260a895869beaa4cab9f8b915e457728f41e561reed@google.com        this->setScale(scale, scale, scale);
2908260a895869beaa4cab9f8b915e457728f41e561reed@google.com    }
2917d68335eb427547606497eb4edea81acce7891f9reed@google.com    inline void preScale(SkMScalar scale) {
2928260a895869beaa4cab9f8b915e457728f41e561reed@google.com        this->preScale(scale, scale, scale);
2938260a895869beaa4cab9f8b915e457728f41e561reed@google.com    }
2947d68335eb427547606497eb4edea81acce7891f9reed@google.com    inline void postScale(SkMScalar scale) {
2958260a895869beaa4cab9f8b915e457728f41e561reed@google.com        this->postScale(scale, scale, scale);
2968260a895869beaa4cab9f8b915e457728f41e561reed@google.com    }
2978260a895869beaa4cab9f8b915e457728f41e561reed@google.com
2988260a895869beaa4cab9f8b915e457728f41e561reed@google.com    void setRotateDegreesAbout(SkMScalar x, SkMScalar y, SkMScalar z,
2998260a895869beaa4cab9f8b915e457728f41e561reed@google.com                               SkMScalar degrees) {
3008260a895869beaa4cab9f8b915e457728f41e561reed@google.com        this->setRotateAbout(x, y, z, degrees * SK_MScalarPI / 180);
3018260a895869beaa4cab9f8b915e457728f41e561reed@google.com    }
3028260a895869beaa4cab9f8b915e457728f41e561reed@google.com
3038260a895869beaa4cab9f8b915e457728f41e561reed@google.com    /** Rotate about the vector [x,y,z]. If that vector is not unit-length,
3048260a895869beaa4cab9f8b915e457728f41e561reed@google.com        it will be automatically resized.
3058260a895869beaa4cab9f8b915e457728f41e561reed@google.com     */
3068260a895869beaa4cab9f8b915e457728f41e561reed@google.com    void setRotateAbout(SkMScalar x, SkMScalar y, SkMScalar z,
3078260a895869beaa4cab9f8b915e457728f41e561reed@google.com                        SkMScalar radians);
3088260a895869beaa4cab9f8b915e457728f41e561reed@google.com    /** Rotate about the vector [x,y,z]. Does not check the length of the
3098260a895869beaa4cab9f8b915e457728f41e561reed@google.com        vector, assuming it is unit-length.
3108260a895869beaa4cab9f8b915e457728f41e561reed@google.com     */
3118260a895869beaa4cab9f8b915e457728f41e561reed@google.com    void setRotateAboutUnit(SkMScalar x, SkMScalar y, SkMScalar z,
3128260a895869beaa4cab9f8b915e457728f41e561reed@google.com                            SkMScalar radians);
3138260a895869beaa4cab9f8b915e457728f41e561reed@google.com
3148260a895869beaa4cab9f8b915e457728f41e561reed@google.com    void setConcat(const SkMatrix44& a, const SkMatrix44& b);
3157d68335eb427547606497eb4edea81acce7891f9reed@google.com    inline void preConcat(const SkMatrix44& m) {
3168260a895869beaa4cab9f8b915e457728f41e561reed@google.com        this->setConcat(*this, m);
3178260a895869beaa4cab9f8b915e457728f41e561reed@google.com    }
3187d68335eb427547606497eb4edea81acce7891f9reed@google.com    inline void postConcat(const SkMatrix44& m) {
3198260a895869beaa4cab9f8b915e457728f41e561reed@google.com        this->setConcat(m, *this);
3208260a895869beaa4cab9f8b915e457728f41e561reed@google.com    }
3218260a895869beaa4cab9f8b915e457728f41e561reed@google.com
3228260a895869beaa4cab9f8b915e457728f41e561reed@google.com    friend SkMatrix44 operator*(const SkMatrix44& a, const SkMatrix44& b) {
3238260a895869beaa4cab9f8b915e457728f41e561reed@google.com        return SkMatrix44(a, b);
3248260a895869beaa4cab9f8b915e457728f41e561reed@google.com    }
3258260a895869beaa4cab9f8b915e457728f41e561reed@google.com
3268260a895869beaa4cab9f8b915e457728f41e561reed@google.com    /** If this is invertible, return that in inverse and return true. If it is
3278260a895869beaa4cab9f8b915e457728f41e561reed@google.com        not invertible, return false and ignore the inverse parameter.
3288260a895869beaa4cab9f8b915e457728f41e561reed@google.com     */
3298260a895869beaa4cab9f8b915e457728f41e561reed@google.com    bool invert(SkMatrix44* inverse) const;
3308260a895869beaa4cab9f8b915e457728f41e561reed@google.com
3319b21c25e742d6a8b69bee8b049e79877f93b5936vollick@chromium.org    /** Transpose this matrix in place. */
3329b21c25e742d6a8b69bee8b049e79877f93b5936vollick@chromium.org    void transpose();
3339b21c25e742d6a8b69bee8b049e79877f93b5936vollick@chromium.org
3348260a895869beaa4cab9f8b915e457728f41e561reed@google.com    /** Apply the matrix to the src vector, returning the new vector in dst.
3358260a895869beaa4cab9f8b915e457728f41e561reed@google.com        It is legal for src and dst to point to the same memory.
3368260a895869beaa4cab9f8b915e457728f41e561reed@google.com     */
3371ea95be560b38a71e3f24749c4e5e3d3564e4c6creed@google.com    void mapScalars(const SkScalar src[4], SkScalar dst[4]) const;
3387d68335eb427547606497eb4edea81acce7891f9reed@google.com    inline void mapScalars(SkScalar vec[4]) const {
3391ea95be560b38a71e3f24749c4e5e3d3564e4c6creed@google.com        this->mapScalars(vec, vec);
3401ea95be560b38a71e3f24749c4e5e3d3564e4c6creed@google.com    }
3411ea95be560b38a71e3f24749c4e5e3d3564e4c6creed@google.com
3424469938e92d779dff05e745559e67907bbf21e78reed@google.com    SK_ATTR_DEPRECATED("use mapScalars")
3431ea95be560b38a71e3f24749c4e5e3d3564e4c6creed@google.com    void map(const SkScalar src[4], SkScalar dst[4]) const {
3441ea95be560b38a71e3f24749c4e5e3d3564e4c6creed@google.com        this->mapScalars(src, dst);
3451ea95be560b38a71e3f24749c4e5e3d3564e4c6creed@google.com    }
3464469938e92d779dff05e745559e67907bbf21e78reed@google.com
3474469938e92d779dff05e745559e67907bbf21e78reed@google.com    SK_ATTR_DEPRECATED("use mapScalars")
3488260a895869beaa4cab9f8b915e457728f41e561reed@google.com    void map(SkScalar vec[4]) const {
3491ea95be560b38a71e3f24749c4e5e3d3564e4c6creed@google.com        this->mapScalars(vec, vec);
3501ea95be560b38a71e3f24749c4e5e3d3564e4c6creed@google.com    }
3511ea95be560b38a71e3f24749c4e5e3d3564e4c6creed@google.com
3521ea95be560b38a71e3f24749c4e5e3d3564e4c6creed@google.com#ifdef SK_MSCALAR_IS_DOUBLE
353dd31131021e2b5ef16b4f3cdec3cf328adcfd6ccreed@google.com    void mapMScalars(const SkMScalar src[4], SkMScalar dst[4]) const;
3545596a69e9f7884e3042bceba071c468dee52aa7fvollick@chromium.org#elif defined SK_MSCALAR_IS_FLOAT
3557d68335eb427547606497eb4edea81acce7891f9reed@google.com    inline void mapMScalars(const SkMScalar src[4], SkMScalar dst[4]) const {
3561ea95be560b38a71e3f24749c4e5e3d3564e4c6creed@google.com        this->mapScalars(src, dst);
3571ea95be560b38a71e3f24749c4e5e3d3564e4c6creed@google.com    }
3581ea95be560b38a71e3f24749c4e5e3d3564e4c6creed@google.com#endif
3597d68335eb427547606497eb4edea81acce7891f9reed@google.com    inline void mapMScalars(SkMScalar vec[4]) const {
3601ea95be560b38a71e3f24749c4e5e3d3564e4c6creed@google.com        this->mapMScalars(vec, vec);
3618260a895869beaa4cab9f8b915e457728f41e561reed@google.com    }
3628260a895869beaa4cab9f8b915e457728f41e561reed@google.com
3638260a895869beaa4cab9f8b915e457728f41e561reed@google.com    friend SkVector4 operator*(const SkMatrix44& m, const SkVector4& src) {
3648260a895869beaa4cab9f8b915e457728f41e561reed@google.com        SkVector4 dst;
3654469938e92d779dff05e745559e67907bbf21e78reed@google.com        m.mapScalars(src.fData, dst.fData);
3668260a895869beaa4cab9f8b915e457728f41e561reed@google.com        return dst;
3678260a895869beaa4cab9f8b915e457728f41e561reed@google.com    }
3688260a895869beaa4cab9f8b915e457728f41e561reed@google.com
36999b5c7f94ba5ef0c9cb464e34834cd5adea37a0ereed@google.com    /**
37099b5c7f94ba5ef0c9cb464e34834cd5adea37a0ereed@google.com     *  map an array of [x, y, 0, 1] through the matrix, returning an array
37199b5c7f94ba5ef0c9cb464e34834cd5adea37a0ereed@google.com     *  of [x', y', z', w'].
37299b5c7f94ba5ef0c9cb464e34834cd5adea37a0ereed@google.com     *
37399b5c7f94ba5ef0c9cb464e34834cd5adea37a0ereed@google.com     *  @param src2     array of [x, y] pairs, with implied z=0 and w=1
37499b5c7f94ba5ef0c9cb464e34834cd5adea37a0ereed@google.com     *  @param count    number of [x, y] pairs in src2
37599b5c7f94ba5ef0c9cb464e34834cd5adea37a0ereed@google.com     *  @param dst4     array of [x', y', z', w'] quads as the output.
37699b5c7f94ba5ef0c9cb464e34834cd5adea37a0ereed@google.com     */
37799b5c7f94ba5ef0c9cb464e34834cd5adea37a0ereed@google.com    void map2(const float src2[], int count, float dst4[]) const;
37899b5c7f94ba5ef0c9cb464e34834cd5adea37a0ereed@google.com    void map2(const double src2[], int count, double dst4[]) const;
37999b5c7f94ba5ef0c9cb464e34834cd5adea37a0ereed@google.com
3808260a895869beaa4cab9f8b915e457728f41e561reed@google.com    void dump() const;
3818260a895869beaa4cab9f8b915e457728f41e561reed@google.com
3823959a76ab086a4adbdb9d48977fa276ce0213cb1vollick@chromium.org    double determinant() const;
3833959a76ab086a4adbdb9d48977fa276ce0213cb1vollick@chromium.org
3848260a895869beaa4cab9f8b915e457728f41e561reed@google.comprivate:
385d53025364a8062b5c72f3f9ed54a613a1ae17958reed@google.com    SkMScalar           fMat[4][4];
386d53025364a8062b5c72f3f9ed54a613a1ae17958reed@google.com    mutable unsigned    fTypeMask;
3870264fb4543b0d8cebe00f1ee32433784f4ceb074skia.committer@gmail.com
3887d68335eb427547606497eb4edea81acce7891f9reed@google.com    enum {
3897d68335eb427547606497eb4edea81acce7891f9reed@google.com        kUnknown_Mask = 0x80,
3907d68335eb427547606497eb4edea81acce7891f9reed@google.com
3917d68335eb427547606497eb4edea81acce7891f9reed@google.com        kAllPublic_Masks = 0xF
3927d68335eb427547606497eb4edea81acce7891f9reed@google.com    };
3937d68335eb427547606497eb4edea81acce7891f9reed@google.com
3947d68335eb427547606497eb4edea81acce7891f9reed@google.com    SkMScalar transX() const { return fMat[3][0]; }
3957d68335eb427547606497eb4edea81acce7891f9reed@google.com    SkMScalar transY() const { return fMat[3][1]; }
3967d68335eb427547606497eb4edea81acce7891f9reed@google.com    SkMScalar transZ() const { return fMat[3][2]; }
3977d68335eb427547606497eb4edea81acce7891f9reed@google.com
3987d68335eb427547606497eb4edea81acce7891f9reed@google.com    SkMScalar scaleX() const { return fMat[0][0]; }
3997d68335eb427547606497eb4edea81acce7891f9reed@google.com    SkMScalar scaleY() const { return fMat[1][1]; }
4007d68335eb427547606497eb4edea81acce7891f9reed@google.com    SkMScalar scaleZ() const { return fMat[2][2]; }
4010264fb4543b0d8cebe00f1ee32433784f4ceb074skia.committer@gmail.com
4027d68335eb427547606497eb4edea81acce7891f9reed@google.com    SkMScalar perspX() const { return fMat[0][3]; }
4037d68335eb427547606497eb4edea81acce7891f9reed@google.com    SkMScalar perspY() const { return fMat[1][3]; }
4047d68335eb427547606497eb4edea81acce7891f9reed@google.com    SkMScalar perspZ() const { return fMat[2][3]; }
405deb4c169690c777acb27ee8ce67d70d3f6eb2a2cjamesr@chromium.org
4067d68335eb427547606497eb4edea81acce7891f9reed@google.com    int computeTypeMask() const;
4077d68335eb427547606497eb4edea81acce7891f9reed@google.com
4087d68335eb427547606497eb4edea81acce7891f9reed@google.com    inline void dirtyTypeMask() {
4097d68335eb427547606497eb4edea81acce7891f9reed@google.com        fTypeMask = kUnknown_Mask;
4107d68335eb427547606497eb4edea81acce7891f9reed@google.com    }
4117d68335eb427547606497eb4edea81acce7891f9reed@google.com
4127d68335eb427547606497eb4edea81acce7891f9reed@google.com    inline void setTypeMask(int mask) {
4137d68335eb427547606497eb4edea81acce7891f9reed@google.com        SkASSERT(0 == (~(kAllPublic_Masks | kUnknown_Mask) & mask));
4147d68335eb427547606497eb4edea81acce7891f9reed@google.com        fTypeMask = mask;
4157d68335eb427547606497eb4edea81acce7891f9reed@google.com    }
4167d68335eb427547606497eb4edea81acce7891f9reed@google.com
4177d68335eb427547606497eb4edea81acce7891f9reed@google.com    /**
4187d68335eb427547606497eb4edea81acce7891f9reed@google.com     *  Does not take the time to 'compute' the typemask. Only returns true if
4197d68335eb427547606497eb4edea81acce7891f9reed@google.com     *  we already know that this matrix is identity.
4207d68335eb427547606497eb4edea81acce7891f9reed@google.com     */
4217d68335eb427547606497eb4edea81acce7891f9reed@google.com    inline bool isTriviallyIdentity() const {
4227d68335eb427547606497eb4edea81acce7891f9reed@google.com        return 0 == fTypeMask;
4237d68335eb427547606497eb4edea81acce7891f9reed@google.com    }
4247cfb9c7b6186bf1e42b7d13466eab94470587e7etomhudson@google.com};
4258260a895869beaa4cab9f8b915e457728f41e561reed@google.com
4268260a895869beaa4cab9f8b915e457728f41e561reed@google.com#endif
427