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
84static const SkMScalar SK_MScalar1 = 1;
85
86///////////////////////////////////////////////////////////////////////////////
87
88struct 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
129class SK_API SkMatrix44 {
130public:
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 ignore the inverse parameter.
362     */
363    bool invert(SkMatrix44* inverse) const;
364
365    /** Transpose this matrix in place. */
366    void transpose();
367
368    /** Apply the matrix to the src vector, returning the new vector in dst.
369        It is legal for src and dst to point to the same memory.
370     */
371    void mapScalars(const SkScalar src[4], SkScalar dst[4]) const;
372    inline void mapScalars(SkScalar vec[4]) const {
373        this->mapScalars(vec, vec);
374    }
375
376    SK_ATTR_DEPRECATED("use mapScalars")
377    void map(const SkScalar src[4], SkScalar dst[4]) const {
378        this->mapScalars(src, dst);
379    }
380
381    SK_ATTR_DEPRECATED("use mapScalars")
382    void map(SkScalar vec[4]) const {
383        this->mapScalars(vec, vec);
384    }
385
386#ifdef SK_MSCALAR_IS_DOUBLE
387    void mapMScalars(const SkMScalar src[4], SkMScalar dst[4]) const;
388#elif defined SK_MSCALAR_IS_FLOAT
389    inline void mapMScalars(const SkMScalar src[4], SkMScalar dst[4]) const {
390        this->mapScalars(src, dst);
391    }
392#endif
393    inline void mapMScalars(SkMScalar vec[4]) const {
394        this->mapMScalars(vec, vec);
395    }
396
397    friend SkVector4 operator*(const SkMatrix44& m, const SkVector4& src) {
398        SkVector4 dst;
399        m.mapScalars(src.fData, dst.fData);
400        return dst;
401    }
402
403    /**
404     *  map an array of [x, y, 0, 1] through the matrix, returning an array
405     *  of [x', y', z', w'].
406     *
407     *  @param src2     array of [x, y] pairs, with implied z=0 and w=1
408     *  @param count    number of [x, y] pairs in src2
409     *  @param dst4     array of [x', y', z', w'] quads as the output.
410     */
411    void map2(const float src2[], int count, float dst4[]) const;
412    void map2(const double src2[], int count, double dst4[]) const;
413
414    /** Returns true if transformating an axis-aligned square in 2d by this matrix
415        will produce another 2d axis-aligned square; typically means the matrix
416        is a scale with perhaps a 90-degree rotation. A 3d rotation through 90
417        degrees into a perpendicular plane collapses a square to a line, but
418        is still considered to be axis-aligned.
419
420        By default, tolerates very slight error due to float imprecisions;
421        a 90-degree rotation can still end up with 10^-17 of
422        "non-axis-aligned" result.
423     */
424    bool preserves2dAxisAlignment(SkMScalar epsilon = SK_ScalarNearlyZero) const;
425
426    void dump() const;
427
428    double determinant() const;
429
430private:
431    SkMScalar           fMat[4][4];
432    mutable unsigned    fTypeMask;
433
434    enum {
435        kUnknown_Mask = 0x80,
436
437        kAllPublic_Masks = 0xF
438    };
439
440    SkMScalar transX() const { return fMat[3][0]; }
441    SkMScalar transY() const { return fMat[3][1]; }
442    SkMScalar transZ() const { return fMat[3][2]; }
443
444    SkMScalar scaleX() const { return fMat[0][0]; }
445    SkMScalar scaleY() const { return fMat[1][1]; }
446    SkMScalar scaleZ() const { return fMat[2][2]; }
447
448    SkMScalar perspX() const { return fMat[0][3]; }
449    SkMScalar perspY() const { return fMat[1][3]; }
450    SkMScalar perspZ() const { return fMat[2][3]; }
451
452    int computeTypeMask() const;
453
454    inline void dirtyTypeMask() {
455        fTypeMask = kUnknown_Mask;
456    }
457
458    inline void setTypeMask(int mask) {
459        SkASSERT(0 == (~(kAllPublic_Masks | kUnknown_Mask) & mask));
460        fTypeMask = mask;
461    }
462
463    /**
464     *  Does not take the time to 'compute' the typemask. Only returns true if
465     *  we already know that this matrix is identity.
466     */
467    inline bool isTriviallyIdentity() const {
468        return 0 == fTypeMask;
469    }
470};
471
472#endif
473