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#include "SkMatrix44.h"
9
10static inline bool eq4(const SkMScalar* SK_RESTRICT a,
11                      const SkMScalar* SK_RESTRICT b) {
12    return (a[0] == b[0]) & (a[1] == b[1]) & (a[2] == b[2]) & (a[3] == b[3]);
13}
14
15bool SkMatrix44::operator==(const SkMatrix44& other) const {
16    if (this == &other) {
17        return true;
18    }
19
20    if (this->isTriviallyIdentity() && other.isTriviallyIdentity()) {
21        return true;
22    }
23
24    const SkMScalar* SK_RESTRICT a = &fMat[0][0];
25    const SkMScalar* SK_RESTRICT b = &other.fMat[0][0];
26
27#if 0
28    for (int i = 0; i < 16; ++i) {
29        if (a[i] != b[i]) {
30            return false;
31        }
32    }
33    return true;
34#else
35    // to reduce branch instructions, we compare 4 at a time.
36    // see bench/Matrix44Bench.cpp for test.
37    if (!eq4(&a[0], &b[0])) {
38        return false;
39    }
40    if (!eq4(&a[4], &b[4])) {
41        return false;
42    }
43    if (!eq4(&a[8], &b[8])) {
44        return false;
45    }
46    return eq4(&a[12], &b[12]);
47#endif
48}
49
50///////////////////////////////////////////////////////////////////////////////
51
52int SkMatrix44::computeTypeMask() const {
53    unsigned mask = 0;
54
55    if (0 != perspX() || 0 != perspY() || 0 != perspZ() || 1 != fMat[3][3]) {
56        return kTranslate_Mask | kScale_Mask | kAffine_Mask | kPerspective_Mask;
57    }
58
59    if (0 != transX() || 0 != transY() || 0 != transZ()) {
60        mask |= kTranslate_Mask;
61    }
62
63    if (1 != scaleX() || 1 != scaleY() || 1 != scaleZ()) {
64        mask |= kScale_Mask;
65    }
66
67    if (0 != fMat[1][0] || 0 != fMat[0][1] || 0 != fMat[0][2] ||
68        0 != fMat[2][0] || 0 != fMat[1][2] || 0 != fMat[2][1]) {
69            mask |= kAffine_Mask;
70    }
71
72    return mask;
73}
74
75///////////////////////////////////////////////////////////////////////////////
76
77void SkMatrix44::asColMajorf(float dst[]) const {
78    const SkMScalar* src = &fMat[0][0];
79#ifdef SK_MSCALAR_IS_DOUBLE
80    for (int i = 0; i < 16; ++i) {
81        dst[i] = SkMScalarToFloat(src[i]);
82    }
83#elif defined SK_MSCALAR_IS_FLOAT
84    memcpy(dst, src, 16 * sizeof(float));
85#endif
86}
87
88void SkMatrix44::asColMajord(double dst[]) const {
89    const SkMScalar* src = &fMat[0][0];
90#ifdef SK_MSCALAR_IS_DOUBLE
91    memcpy(dst, src, 16 * sizeof(double));
92#elif defined SK_MSCALAR_IS_FLOAT
93    for (int i = 0; i < 16; ++i) {
94        dst[i] = SkMScalarToDouble(src[i]);
95    }
96#endif
97}
98
99void SkMatrix44::asRowMajorf(float dst[]) const {
100    const SkMScalar* src = &fMat[0][0];
101    for (int i = 0; i < 4; ++i) {
102        dst[0] = SkMScalarToFloat(src[0]);
103        dst[4] = SkMScalarToFloat(src[1]);
104        dst[8] = SkMScalarToFloat(src[2]);
105        dst[12] = SkMScalarToFloat(src[3]);
106        src += 4;
107        dst += 1;
108    }
109}
110
111void SkMatrix44::asRowMajord(double dst[]) const {
112    const SkMScalar* src = &fMat[0][0];
113    for (int i = 0; i < 4; ++i) {
114        dst[0] = SkMScalarToDouble(src[0]);
115        dst[4] = SkMScalarToDouble(src[1]);
116        dst[8] = SkMScalarToDouble(src[2]);
117        dst[12] = SkMScalarToDouble(src[3]);
118        src += 4;
119        dst += 1;
120    }
121}
122
123void SkMatrix44::setColMajorf(const float src[]) {
124    SkMScalar* dst = &fMat[0][0];
125#ifdef SK_MSCALAR_IS_DOUBLE
126    for (int i = 0; i < 16; ++i) {
127        dst[i] = SkMScalarToFloat(src[i]);
128    }
129#elif defined SK_MSCALAR_IS_FLOAT
130    memcpy(dst, src, 16 * sizeof(float));
131#endif
132
133    this->dirtyTypeMask();
134}
135
136void SkMatrix44::setColMajord(const double src[]) {
137    SkMScalar* dst = &fMat[0][0];
138#ifdef SK_MSCALAR_IS_DOUBLE
139    memcpy(dst, src, 16 * sizeof(double));
140#elif defined SK_MSCALAR_IS_FLOAT
141    for (int i = 0; i < 16; ++i) {
142        dst[i] = SkDoubleToMScalar(src[i]);
143    }
144#endif
145
146    this->dirtyTypeMask();
147}
148
149void SkMatrix44::setRowMajorf(const float src[]) {
150    SkMScalar* dst = &fMat[0][0];
151    for (int i = 0; i < 4; ++i) {
152        dst[0] = SkMScalarToFloat(src[0]);
153        dst[4] = SkMScalarToFloat(src[1]);
154        dst[8] = SkMScalarToFloat(src[2]);
155        dst[12] = SkMScalarToFloat(src[3]);
156        src += 4;
157        dst += 1;
158    }
159    this->dirtyTypeMask();
160}
161
162void SkMatrix44::setRowMajord(const double src[]) {
163    SkMScalar* dst = &fMat[0][0];
164    for (int i = 0; i < 4; ++i) {
165        dst[0] = SkDoubleToMScalar(src[0]);
166        dst[4] = SkDoubleToMScalar(src[1]);
167        dst[8] = SkDoubleToMScalar(src[2]);
168        dst[12] = SkDoubleToMScalar(src[3]);
169        src += 4;
170        dst += 1;
171    }
172    this->dirtyTypeMask();
173}
174
175///////////////////////////////////////////////////////////////////////////////
176
177const SkMatrix44& SkMatrix44::I() {
178    static const SkMatrix44 gIdentity44(kIdentity_Constructor);
179    return gIdentity44;
180}
181
182void SkMatrix44::setIdentity() {
183    sk_bzero(fMat, sizeof(fMat));
184    fMat[0][0] = fMat[1][1] = fMat[2][2] = fMat[3][3] = 1;
185    this->setTypeMask(kIdentity_Mask);
186}
187
188void SkMatrix44::set3x3(SkMScalar m00, SkMScalar m01, SkMScalar m02,
189                        SkMScalar m10, SkMScalar m11, SkMScalar m12,
190                        SkMScalar m20, SkMScalar m21, SkMScalar m22) {
191    fMat[0][0] = m00; fMat[0][1] = m01; fMat[0][2] = m02; fMat[0][3] = 0;
192    fMat[1][0] = m10; fMat[1][1] = m11; fMat[1][2] = m12; fMat[1][3] = 0;
193    fMat[2][0] = m20; fMat[2][1] = m21; fMat[2][2] = m22; fMat[2][3] = 0;
194    fMat[3][0] = 0;   fMat[3][1] = 0;   fMat[3][2] = 0;   fMat[3][3] = 1;
195    this->dirtyTypeMask();
196}
197
198///////////////////////////////////////////////////////////////////////////////
199
200void SkMatrix44::setTranslate(SkMScalar dx, SkMScalar dy, SkMScalar dz) {
201    this->setIdentity();
202
203    if (!dx && !dy && !dz) {
204        return;
205    }
206
207    fMat[3][0] = dx;
208    fMat[3][1] = dy;
209    fMat[3][2] = dz;
210    this->setTypeMask(kTranslate_Mask);
211}
212
213void SkMatrix44::preTranslate(SkMScalar dx, SkMScalar dy, SkMScalar dz) {
214    if (!dx && !dy && !dz) {
215        return;
216    }
217
218    const double X = SkMScalarToDouble(dx);
219    const double Y = SkMScalarToDouble(dy);
220    const double Z = SkMScalarToDouble(dz);
221
222    double tmp;
223    for (int i = 0; i < 4; ++i) {
224        tmp = fMat[0][i] * X + fMat[1][i] * Y + fMat[2][i] * Z + fMat[3][i];
225        fMat[3][i] = SkDoubleToMScalar(tmp);
226    }
227    this->dirtyTypeMask();
228}
229
230void SkMatrix44::postTranslate(SkMScalar dx, SkMScalar dy, SkMScalar dz) {
231    if (!dx && !dy && !dz) {
232        return;
233    }
234
235    if (this->getType() & kPerspective_Mask) {
236        for (int i = 0; i < 4; ++i) {
237            fMat[i][0] += fMat[i][3] * dx;
238            fMat[i][1] += fMat[i][3] * dy;
239            fMat[i][2] += fMat[i][3] * dz;
240        }
241    } else {
242        fMat[3][0] += dx;
243        fMat[3][1] += dy;
244        fMat[3][2] += dz;
245        this->dirtyTypeMask();
246    }
247}
248
249///////////////////////////////////////////////////////////////////////////////
250
251void SkMatrix44::setScale(SkMScalar sx, SkMScalar sy, SkMScalar sz) {
252    this->setIdentity();
253
254    if (1 == sx && 1 == sy && 1 == sz) {
255        return;
256    }
257
258    fMat[0][0] = sx;
259    fMat[1][1] = sy;
260    fMat[2][2] = sz;
261    this->setTypeMask(kScale_Mask);
262}
263
264void SkMatrix44::preScale(SkMScalar sx, SkMScalar sy, SkMScalar sz) {
265    if (1 == sx && 1 == sy && 1 == sz) {
266        return;
267    }
268
269    // The implementation matrix * pureScale can be shortcut
270    // by knowing that pureScale components effectively scale
271    // the columns of the original matrix.
272    for (int i = 0; i < 4; i++) {
273        fMat[0][i] *= sx;
274        fMat[1][i] *= sy;
275        fMat[2][i] *= sz;
276    }
277    this->dirtyTypeMask();
278}
279
280void SkMatrix44::postScale(SkMScalar sx, SkMScalar sy, SkMScalar sz) {
281    if (1 == sx && 1 == sy && 1 == sz) {
282        return;
283    }
284
285    for (int i = 0; i < 4; i++) {
286        fMat[i][0] *= sx;
287        fMat[i][1] *= sy;
288        fMat[i][2] *= sz;
289    }
290    this->dirtyTypeMask();
291}
292
293///////////////////////////////////////////////////////////////////////////////
294
295void SkMatrix44::setRotateAbout(SkMScalar x, SkMScalar y, SkMScalar z,
296                                SkMScalar radians) {
297    double len2 = (double)x * x + (double)y * y + (double)z * z;
298    if (1 != len2) {
299        if (0 == len2) {
300            this->setIdentity();
301            return;
302        }
303        double scale = 1 / sqrt(len2);
304        x = SkDoubleToMScalar(x * scale);
305        y = SkDoubleToMScalar(y * scale);
306        z = SkDoubleToMScalar(z * scale);
307    }
308    this->setRotateAboutUnit(x, y, z, radians);
309}
310
311void SkMatrix44::setRotateAboutUnit(SkMScalar x, SkMScalar y, SkMScalar z,
312                                    SkMScalar radians) {
313    double c = cos(radians);
314    double s = sin(radians);
315    double C = 1 - c;
316    double xs = x * s;
317    double ys = y * s;
318    double zs = z * s;
319    double xC = x * C;
320    double yC = y * C;
321    double zC = z * C;
322    double xyC = x * yC;
323    double yzC = y * zC;
324    double zxC = z * xC;
325
326    // if you're looking at wikipedia, remember that we're column major.
327    this->set3x3(SkDoubleToMScalar(x * xC + c),     // scale x
328                 SkDoubleToMScalar(xyC + zs),       // skew x
329                 SkDoubleToMScalar(zxC - ys),       // trans x
330
331                 SkDoubleToMScalar(xyC - zs),       // skew y
332                 SkDoubleToMScalar(y * yC + c),     // scale y
333                 SkDoubleToMScalar(yzC + xs),       // trans y
334
335                 SkDoubleToMScalar(zxC + ys),       // persp x
336                 SkDoubleToMScalar(yzC - xs),       // persp y
337                 SkDoubleToMScalar(z * zC + c));    // persp 2
338}
339
340///////////////////////////////////////////////////////////////////////////////
341
342static bool bits_isonly(int value, int mask) {
343    return 0 == (value & ~mask);
344}
345
346void SkMatrix44::setConcat(const SkMatrix44& a, const SkMatrix44& b) {
347    const SkMatrix44::TypeMask a_mask = a.getType();
348    const SkMatrix44::TypeMask b_mask = b.getType();
349
350    if (kIdentity_Mask == a_mask) {
351        *this = b;
352        return;
353    }
354    if (kIdentity_Mask == b_mask) {
355        *this = a;
356        return;
357    }
358
359    bool useStorage = (this == &a || this == &b);
360    SkMScalar storage[16];
361    SkMScalar* result = useStorage ? storage : &fMat[0][0];
362
363    // Both matrices are at most scale+translate
364    if (bits_isonly(a_mask | b_mask, kScale_Mask | kTranslate_Mask)) {
365        result[0] = a.fMat[0][0] * b.fMat[0][0];
366        result[1] = result[2] = result[3] = result[4] = 0;
367        result[5] = a.fMat[1][1] * b.fMat[1][1];
368        result[6] = result[7] = result[8] = result[9] = 0;
369        result[10] = a.fMat[2][2] * b.fMat[2][2];
370        result[11] = 0;
371        result[12] = a.fMat[0][0] * b.fMat[3][0] + a.fMat[3][0];
372        result[13] = a.fMat[1][1] * b.fMat[3][1] + a.fMat[3][1];
373        result[14] = a.fMat[2][2] * b.fMat[3][2] + a.fMat[3][2];
374        result[15] = 1;
375    } else {
376        for (int j = 0; j < 4; j++) {
377            for (int i = 0; i < 4; i++) {
378                double value = 0;
379                for (int k = 0; k < 4; k++) {
380                    value += SkMScalarToDouble(a.fMat[k][i]) * b.fMat[j][k];
381                }
382                *result++ = SkDoubleToMScalar(value);
383            }
384        }
385    }
386
387    if (useStorage) {
388        memcpy(fMat, storage, sizeof(storage));
389    }
390    this->dirtyTypeMask();
391}
392
393///////////////////////////////////////////////////////////////////////////////
394
395static inline SkMScalar det2x2(double m00, double m01, double m10, double m11) {
396    return SkDoubleToMScalar(m00 * m11 - m10 * m01);
397}
398
399static inline double det3x3(double m00, double m01, double m02,
400                            double m10, double m11, double m12,
401                            double m20, double m21, double m22) {
402    return  m00 * det2x2(m11, m12, m21, m22) -
403    m10 * det2x2(m01, m02, m21, m22) +
404    m20 * det2x2(m01, m02, m11, m12);
405}
406
407/** We always perform the calculation in doubles, to avoid prematurely losing
408    precision along the way. This relies on the compiler automatically
409    promoting our SkMScalar values to double (if needed).
410 */
411double SkMatrix44::determinant() const {
412    if (this->isIdentity()) {
413        return 1;
414    }
415    if (this->isScaleTranslate()) {
416        return fMat[0][0] * fMat[1][1] * fMat[2][2] * fMat[3][3];
417    }
418
419    double a00 = fMat[0][0];
420    double a01 = fMat[0][1];
421    double a02 = fMat[0][2];
422    double a03 = fMat[0][3];
423    double a10 = fMat[1][0];
424    double a11 = fMat[1][1];
425    double a12 = fMat[1][2];
426    double a13 = fMat[1][3];
427    double a20 = fMat[2][0];
428    double a21 = fMat[2][1];
429    double a22 = fMat[2][2];
430    double a23 = fMat[2][3];
431    double a30 = fMat[3][0];
432    double a31 = fMat[3][1];
433    double a32 = fMat[3][2];
434    double a33 = fMat[3][3];
435
436    double b00 = a00 * a11 - a01 * a10;
437    double b01 = a00 * a12 - a02 * a10;
438    double b02 = a00 * a13 - a03 * a10;
439    double b03 = a01 * a12 - a02 * a11;
440    double b04 = a01 * a13 - a03 * a11;
441    double b05 = a02 * a13 - a03 * a12;
442    double b06 = a20 * a31 - a21 * a30;
443    double b07 = a20 * a32 - a22 * a30;
444    double b08 = a20 * a33 - a23 * a30;
445    double b09 = a21 * a32 - a22 * a31;
446    double b10 = a21 * a33 - a23 * a31;
447    double b11 = a22 * a33 - a23 * a32;
448
449    // Calculate the determinant
450    return b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
451}
452
453///////////////////////////////////////////////////////////////////////////////
454
455// just picked a small value. not sure how to pick the "right" one
456#define TOO_SMALL_FOR_DETERMINANT   (1.e-8)
457
458static inline double dabs(double x) {
459    if (x < 0) {
460        x = -x;
461    }
462    return x;
463}
464
465bool SkMatrix44::invert(SkMatrix44* inverse) const {
466    if (this->isIdentity()) {
467        if (inverse) {
468            *inverse = *this;
469            return true;
470        }
471    }
472    if (this->isTranslate()) {
473        if (inverse) {
474            inverse->setTranslate(-fMat[3][0], -fMat[3][1], -fMat[3][2]);
475        }
476        return true;
477    }
478    if (this->isScaleTranslate()) {
479        if (0 == fMat[0][0] * fMat[1][1] * fMat[2][2]) {
480            return false;
481        }
482        if (inverse) {
483            sk_bzero(inverse->fMat, sizeof(inverse->fMat));
484
485            inverse->fMat[3][0] = -fMat[3][0] / fMat[0][0];
486            inverse->fMat[3][1] = -fMat[3][1] / fMat[1][1];
487            inverse->fMat[3][2] = -fMat[3][2] / fMat[2][2];
488
489            inverse->fMat[0][0] = 1 / fMat[0][0];
490            inverse->fMat[1][1] = 1 / fMat[1][1];
491            inverse->fMat[2][2] = 1 / fMat[2][2];
492            inverse->fMat[3][3] = 1;
493
494            inverse->setTypeMask(this->getType());
495        }
496        return true;
497    }
498
499    double a00 = fMat[0][0];
500    double a01 = fMat[0][1];
501    double a02 = fMat[0][2];
502    double a03 = fMat[0][3];
503    double a10 = fMat[1][0];
504    double a11 = fMat[1][1];
505    double a12 = fMat[1][2];
506    double a13 = fMat[1][3];
507    double a20 = fMat[2][0];
508    double a21 = fMat[2][1];
509    double a22 = fMat[2][2];
510    double a23 = fMat[2][3];
511    double a30 = fMat[3][0];
512    double a31 = fMat[3][1];
513    double a32 = fMat[3][2];
514    double a33 = fMat[3][3];
515
516    double b00 = a00 * a11 - a01 * a10;
517    double b01 = a00 * a12 - a02 * a10;
518    double b02 = a00 * a13 - a03 * a10;
519    double b03 = a01 * a12 - a02 * a11;
520    double b04 = a01 * a13 - a03 * a11;
521    double b05 = a02 * a13 - a03 * a12;
522    double b06 = a20 * a31 - a21 * a30;
523    double b07 = a20 * a32 - a22 * a30;
524    double b08 = a20 * a33 - a23 * a30;
525    double b09 = a21 * a32 - a22 * a31;
526    double b10 = a21 * a33 - a23 * a31;
527    double b11 = a22 * a33 - a23 * a32;
528
529    // Calculate the determinant
530    double det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
531
532    if (dabs(det) < TOO_SMALL_FOR_DETERMINANT) {
533        return false;
534    }
535    if (NULL == inverse) {
536        return true;
537    }
538    double invdet = 1.0 / det;
539
540    b00 *= invdet;
541    b01 *= invdet;
542    b02 *= invdet;
543    b03 *= invdet;
544    b04 *= invdet;
545    b05 *= invdet;
546    b06 *= invdet;
547    b07 *= invdet;
548    b08 *= invdet;
549    b09 *= invdet;
550    b10 *= invdet;
551    b11 *= invdet;
552
553    inverse->fMat[0][0] = SkDoubleToMScalar(a11 * b11 - a12 * b10 + a13 * b09);
554    inverse->fMat[0][1] = SkDoubleToMScalar(a02 * b10 - a01 * b11 - a03 * b09);
555    inverse->fMat[0][2] = SkDoubleToMScalar(a31 * b05 - a32 * b04 + a33 * b03);
556    inverse->fMat[0][3] = SkDoubleToMScalar(a22 * b04 - a21 * b05 - a23 * b03);
557    inverse->fMat[1][0] = SkDoubleToMScalar(a12 * b08 - a10 * b11 - a13 * b07);
558    inverse->fMat[1][1] = SkDoubleToMScalar(a00 * b11 - a02 * b08 + a03 * b07);
559    inverse->fMat[1][2] = SkDoubleToMScalar(a32 * b02 - a30 * b05 - a33 * b01);
560    inverse->fMat[1][3] = SkDoubleToMScalar(a20 * b05 - a22 * b02 + a23 * b01);
561    inverse->fMat[2][0] = SkDoubleToMScalar(a10 * b10 - a11 * b08 + a13 * b06);
562    inverse->fMat[2][1] = SkDoubleToMScalar(a01 * b08 - a00 * b10 - a03 * b06);
563    inverse->fMat[2][2] = SkDoubleToMScalar(a30 * b04 - a31 * b02 + a33 * b00);
564    inverse->fMat[2][3] = SkDoubleToMScalar(a21 * b02 - a20 * b04 - a23 * b00);
565    inverse->fMat[3][0] = SkDoubleToMScalar(a11 * b07 - a10 * b09 - a12 * b06);
566    inverse->fMat[3][1] = SkDoubleToMScalar(a00 * b09 - a01 * b07 + a02 * b06);
567    inverse->fMat[3][2] = SkDoubleToMScalar(a31 * b01 - a30 * b03 - a32 * b00);
568    inverse->fMat[3][3] = SkDoubleToMScalar(a20 * b03 - a21 * b01 + a22 * b00);
569    inverse->dirtyTypeMask();
570
571    inverse->dirtyTypeMask();
572    return true;
573}
574
575///////////////////////////////////////////////////////////////////////////////
576
577void SkMatrix44::transpose() {
578    SkTSwap(fMat[0][1], fMat[1][0]);
579    SkTSwap(fMat[0][2], fMat[2][0]);
580    SkTSwap(fMat[0][3], fMat[3][0]);
581    SkTSwap(fMat[1][2], fMat[2][1]);
582    SkTSwap(fMat[1][3], fMat[3][1]);
583    SkTSwap(fMat[2][3], fMat[3][2]);
584
585    if (!this->isTriviallyIdentity()) {
586        this->dirtyTypeMask();
587    }
588}
589
590///////////////////////////////////////////////////////////////////////////////
591
592void SkMatrix44::mapScalars(const SkScalar src[4], SkScalar dst[4]) const {
593    SkScalar storage[4];
594    SkScalar* result = (src == dst) ? storage : dst;
595
596    for (int i = 0; i < 4; i++) {
597        SkMScalar value = 0;
598        for (int j = 0; j < 4; j++) {
599            value += fMat[j][i] * src[j];
600        }
601        result[i] = SkMScalarToScalar(value);
602    }
603
604    if (storage == result) {
605        memcpy(dst, storage, sizeof(storage));
606    }
607}
608
609#ifdef SK_MSCALAR_IS_DOUBLE
610
611void SkMatrix44::mapMScalars(const SkMScalar src[4], SkMScalar dst[4]) const {
612    SkMScalar storage[4];
613    SkMScalar* result = (src == dst) ? storage : dst;
614
615    for (int i = 0; i < 4; i++) {
616        SkMScalar value = 0;
617        for (int j = 0; j < 4; j++) {
618            value += fMat[j][i] * src[j];
619        }
620        result[i] = value;
621    }
622
623    if (storage == result) {
624        memcpy(dst, storage, sizeof(storage));
625    }
626}
627
628#endif
629
630typedef void (*Map2Procf)(const SkMScalar mat[][4], const float src2[], int count, float dst4[]);
631typedef void (*Map2Procd)(const SkMScalar mat[][4], const double src2[], int count, double dst4[]);
632
633static void map2_if(const SkMScalar mat[][4], const float* SK_RESTRICT src2,
634                    int count, float* SK_RESTRICT dst4) {
635    for (int i = 0; i < count; ++i) {
636        dst4[0] = src2[0];
637        dst4[1] = src2[1];
638        dst4[2] = 0;
639        dst4[3] = 1;
640        src2 += 2;
641        dst4 += 4;
642    }
643}
644
645static void map2_id(const SkMScalar mat[][4], const double* SK_RESTRICT src2,
646                    int count, double* SK_RESTRICT dst4) {
647    for (int i = 0; i < count; ++i) {
648        dst4[0] = src2[0];
649        dst4[1] = src2[1];
650        dst4[2] = 0;
651        dst4[3] = 1;
652        src2 += 2;
653        dst4 += 4;
654    }
655}
656
657static void map2_tf(const SkMScalar mat[][4], const float* SK_RESTRICT src2,
658                    int count, float* SK_RESTRICT dst4) {
659    const float mat30 = SkMScalarToFloat(mat[3][0]);
660    const float mat31 = SkMScalarToFloat(mat[3][1]);
661    const float mat32 = SkMScalarToFloat(mat[3][2]);
662    for (int n = 0; n < count; ++n) {
663        dst4[0] = src2[0] + mat30;
664        dst4[1] = src2[1] + mat31;
665        dst4[2] = mat32;
666        dst4[3] = 1;
667        src2 += 2;
668        dst4 += 4;
669    }
670}
671
672static void map2_td(const SkMScalar mat[][4], const double* SK_RESTRICT src2,
673                    int count, double* SK_RESTRICT dst4) {
674    for (int n = 0; n < count; ++n) {
675        dst4[0] = src2[0] + mat[3][0];
676        dst4[1] = src2[1] + mat[3][1];
677        dst4[2] = mat[3][2];
678        dst4[3] = 1;
679        src2 += 2;
680        dst4 += 4;
681    }
682}
683
684static void map2_sf(const SkMScalar mat[][4], const float* SK_RESTRICT src2,
685                    int count, float* SK_RESTRICT dst4) {
686    const float mat32 = SkMScalarToFloat(mat[3][2]);
687    for (int n = 0; n < count; ++n) {
688        dst4[0] = SkMScalarToFloat(mat[0][0] * src2[0] + mat[3][0]);
689        dst4[1] = SkMScalarToFloat(mat[1][1] * src2[1] + mat[3][1]);
690        dst4[2] = mat32;
691        dst4[3] = 1;
692        src2 += 2;
693        dst4 += 4;
694    }
695}
696
697static void map2_sd(const SkMScalar mat[][4], const double* SK_RESTRICT src2,
698                    int count, double* SK_RESTRICT dst4) {
699    for (int n = 0; n < count; ++n) {
700        dst4[0] = mat[0][0] * src2[0] + mat[3][0];
701        dst4[1] = mat[1][1] * src2[1] + mat[3][1];
702        dst4[2] = mat[3][2];
703        dst4[3] = 1;
704        src2 += 2;
705        dst4 += 4;
706    }
707}
708
709static void map2_af(const SkMScalar mat[][4], const float* SK_RESTRICT src2,
710                    int count, float* SK_RESTRICT dst4) {
711    double r;
712    for (int n = 0; n < count; ++n) {
713        double sx = src2[0];
714        double sy = src2[1];
715        r = mat[0][0] * sx + mat[1][0] * sy + mat[3][0];
716        dst4[0] = SkMScalarToFloat(r);
717        r = mat[0][1] * sx + mat[1][1] * sy + mat[3][1];
718        dst4[1] = SkMScalarToFloat(r);
719        r = mat[0][2] * sx + mat[1][2] * sy + mat[3][2];
720        dst4[2] = SkMScalarToFloat(r);
721        dst4[3] = 1;
722        src2 += 2;
723        dst4 += 4;
724    }
725}
726
727static void map2_ad(const SkMScalar mat[][4], const double* SK_RESTRICT src2,
728                    int count, double* SK_RESTRICT dst4) {
729    for (int n = 0; n < count; ++n) {
730        double sx = src2[0];
731        double sy = src2[1];
732        dst4[0] = mat[0][0] * sx + mat[1][0] * sy + mat[3][0];
733        dst4[1] = mat[0][1] * sx + mat[1][1] * sy + mat[3][1];
734        dst4[2] = mat[0][2] * sx + mat[1][2] * sy + mat[3][2];
735        dst4[3] = 1;
736        src2 += 2;
737        dst4 += 4;
738    }
739}
740
741static void map2_pf(const SkMScalar mat[][4], const float* SK_RESTRICT src2,
742                    int count, float* SK_RESTRICT dst4) {
743    double r;
744    for (int n = 0; n < count; ++n) {
745        double sx = src2[0];
746        double sy = src2[1];
747        for (int i = 0; i < 4; i++) {
748            r = mat[0][i] * sx + mat[1][i] * sy + mat[3][i];
749            dst4[i] = SkMScalarToFloat(r);
750        }
751        src2 += 2;
752        dst4 += 4;
753    }
754}
755
756static void map2_pd(const SkMScalar mat[][4], const double* SK_RESTRICT src2,
757                    int count, double* SK_RESTRICT dst4) {
758    for (int n = 0; n < count; ++n) {
759        double sx = src2[0];
760        double sy = src2[1];
761        for (int i = 0; i < 4; i++) {
762            dst4[i] = mat[0][i] * sx + mat[1][i] * sy + mat[3][i];
763        }
764        src2 += 2;
765        dst4 += 4;
766    }
767}
768
769void SkMatrix44::map2(const float src2[], int count, float dst4[]) const {
770    static const Map2Procf gProc[] = {
771        map2_if, map2_tf, map2_sf, map2_sf, map2_af, map2_af, map2_af, map2_af
772    };
773
774    TypeMask mask = this->getType();
775    Map2Procf proc = (mask & kPerspective_Mask) ? map2_pf : gProc[mask];
776    proc(fMat, src2, count, dst4);
777}
778
779void SkMatrix44::map2(const double src2[], int count, double dst4[]) const {
780    static const Map2Procd gProc[] = {
781        map2_id, map2_td, map2_sd, map2_sd, map2_ad, map2_ad, map2_ad, map2_ad
782    };
783
784    TypeMask mask = this->getType();
785    Map2Procd proc = (mask & kPerspective_Mask) ? map2_pd : gProc[mask];
786    proc(fMat, src2, count, dst4);
787}
788
789///////////////////////////////////////////////////////////////////////////////
790
791void SkMatrix44::dump() const {
792    static const char* format =
793        "[%g %g %g %g][%g %g %g %g][%g %g %g %g][%g %g %g %g]\n";
794#if 0
795    SkDebugf(format,
796             fMat[0][0], fMat[1][0], fMat[2][0], fMat[3][0],
797             fMat[0][1], fMat[1][1], fMat[2][1], fMat[3][1],
798             fMat[0][2], fMat[1][2], fMat[2][2], fMat[3][2],
799             fMat[0][3], fMat[1][3], fMat[2][3], fMat[3][3]);
800#else
801    SkDebugf(format,
802             fMat[0][0], fMat[0][1], fMat[0][2], fMat[0][3],
803             fMat[1][0], fMat[1][1], fMat[1][2], fMat[1][3],
804             fMat[2][0], fMat[2][1], fMat[2][2], fMat[2][3],
805             fMat[3][0], fMat[3][1], fMat[3][2], fMat[3][3]);
806#endif
807}
808
809///////////////////////////////////////////////////////////////////////////////
810
811// TODO: make this support src' perspective elements
812//
813static void initFromMatrix(SkMScalar dst[4][4], const SkMatrix& src) {
814    sk_bzero(dst, 16 * sizeof(SkMScalar));
815    dst[0][0] = SkScalarToMScalar(src[SkMatrix::kMScaleX]);
816    dst[1][0] = SkScalarToMScalar(src[SkMatrix::kMSkewX]);
817    dst[3][0] = SkScalarToMScalar(src[SkMatrix::kMTransX]);
818    dst[0][1] = SkScalarToMScalar(src[SkMatrix::kMSkewY]);
819    dst[1][1] = SkScalarToMScalar(src[SkMatrix::kMScaleY]);
820    dst[3][1] = SkScalarToMScalar(src[SkMatrix::kMTransY]);
821    dst[2][2] = dst[3][3] = 1;
822}
823
824SkMatrix44::SkMatrix44(const SkMatrix& src) {
825    initFromMatrix(fMat, src);
826}
827
828SkMatrix44& SkMatrix44::operator=(const SkMatrix& src) {
829    initFromMatrix(fMat, src);
830
831    if (src.isIdentity()) {
832        this->setTypeMask(kIdentity_Mask);
833    } else {
834        this->dirtyTypeMask();
835    }
836    return *this;
837}
838
839// TODO: make this support our perspective elements
840//
841SkMatrix44::operator SkMatrix() const {
842    SkMatrix dst;
843    dst.reset();    // setup our perspective correctly for identity
844
845    dst[SkMatrix::kMScaleX]  = SkMScalarToScalar(fMat[0][0]);
846    dst[SkMatrix::kMSkewX]  = SkMScalarToScalar(fMat[1][0]);
847    dst[SkMatrix::kMTransX] = SkMScalarToScalar(fMat[3][0]);
848
849    dst[SkMatrix::kMSkewY]  = SkMScalarToScalar(fMat[0][1]);
850    dst[SkMatrix::kMScaleY] = SkMScalarToScalar(fMat[1][1]);
851    dst[SkMatrix::kMTransY] = SkMScalarToScalar(fMat[3][1]);
852
853    return dst;
854}
855