blob: 1b1b93b98883e9ff3852181673a8fe53ed6d5fec [file] [log] [blame]
reed@android.com6d342a42010-02-23 20:18:17 +00001#include "SkMatrix44.h"
2
3SkMatrix44::SkMatrix44() {
4 this->setIdentity();
5}
6
7SkMatrix44::SkMatrix44(const SkMatrix44& src) {
8 memcpy(this, &src, sizeof(src));
9}
10
11SkMatrix44::SkMatrix44(const SkMatrix44& a, const SkMatrix44& b) {
12 this->setConcat(a, b);
13}
14
15///////////////////////////////////////////////////////////////////////////////
16
reed@android.comc8c49c52010-02-24 15:36:57 +000017static const SkMatrix44 gIdentity44;
18
19bool SkMatrix44::isIdentity() const {
20 return *this == gIdentity44;
21}
22
23///////////////////////////////////////////////////////////////////////////////
24
reed@android.com6d342a42010-02-23 20:18:17 +000025void SkMatrix44::setIdentity() {
26 sk_bzero(fMat, sizeof(fMat));
27 fMat[0][0] = fMat[1][1] = fMat[2][2] = fMat[3][3] = SK_MScalar1;
28}
29
30void SkMatrix44::setTranslate(SkMScalar tx, SkMScalar ty, SkMScalar tz) {
reed@android.comc8c49c52010-02-24 15:36:57 +000031 this->setIdentity();
reed@android.com6d342a42010-02-23 20:18:17 +000032 fMat[3][0] = tx;
33 fMat[3][1] = ty;
34 fMat[3][2] = tz;
35 fMat[3][3] = SK_MScalar1;
36}
37
38void SkMatrix44::preTranslate(SkMScalar dx, SkMScalar dy, SkMScalar dz) {
39 SkMatrix44 mat;
40 mat.setTranslate(dx, dy, dz);
41 this->preConcat(mat);
42}
43
44void SkMatrix44::postTranslate(SkMScalar dx, SkMScalar dy, SkMScalar dz) {
45 fMat[3][0] += dx;
46 fMat[3][1] += dy;
47 fMat[3][2] += dz;
48}
49
50///////////////////////////////////////////////////////////////////////////////
51
52void SkMatrix44::setScale(SkMScalar sx, SkMScalar sy, SkMScalar sz) {
53 sk_bzero(fMat, sizeof(fMat));
54 fMat[0][0] = sx;
55 fMat[1][1] = sy;
56 fMat[2][2] = sz;
57 fMat[3][3] = SK_MScalar1;
58}
59
60void SkMatrix44::preScale(SkMScalar sx, SkMScalar sy, SkMScalar sz) {
61 SkMatrix44 tmp;
62 tmp.setScale(sx, sy, sz);
63 this->preConcat(tmp);
64}
65
66void SkMatrix44::postScale(SkMScalar sx, SkMScalar sy, SkMScalar sz) {
67 for (int i = 0; i < 4; i++) {
68 fMat[i][0] *= sx;
69 fMat[i][1] *= sy;
70 fMat[i][2] *= sz;
71 }
72}
73
74///////////////////////////////////////////////////////////////////////////////
75
76void SkMatrix44::setConcat(const SkMatrix44& a, const SkMatrix44& b) {
77 SkMScalar result[4][4];
78 for (int i = 0; i < 4; i++) {
79 for (int j = 0; j < 4; j++) {
80 double value = 0;
81 for (int k = 0; k < 4; k++) {
reed@android.comc8c49c52010-02-24 15:36:57 +000082 value += SkMScalarToDouble(a.fMat[k][i]) * b.fMat[j][k];
reed@android.com6d342a42010-02-23 20:18:17 +000083 }
84 result[j][i] = SkDoubleToMScalar(value);
85 }
86 }
87 memcpy(fMat, result, sizeof(result));
88}
89
90///////////////////////////////////////////////////////////////////////////////
91
92static inline SkMScalar det2x2(double m00, double m01, double m10, double m11) {
93 return m00 * m11 - m10 * m01;
94}
95
96static inline double det3x3(double m00, double m01, double m02,
97 double m10, double m11, double m12,
98 double m20, double m21, double m22) {
99 return m00 * det2x2(m11, m12, m21, m22) -
100 m10 * det2x2(m01, m02, m21, m22) +
101 m20 * det2x2(m01, m02, m11, m12);
102}
103
104/** We always perform the calculation in doubles, to avoid prematurely losing
105 precision along the way. This relies on the compiler automatically
106 promoting our SkMScalar values to double (if needed).
107 */
108double SkMatrix44::determinant() const {
109 return fMat[0][0] * det3x3(fMat[1][1], fMat[1][2], fMat[1][3],
110 fMat[2][1], fMat[2][2], fMat[2][3],
111 fMat[3][1], fMat[3][2], fMat[3][3]) -
112 fMat[1][0] * det3x3(fMat[0][1], fMat[0][2], fMat[0][3],
113 fMat[2][1], fMat[2][2], fMat[2][3],
114 fMat[3][1], fMat[3][2], fMat[3][3]) +
115 fMat[2][0] * det3x3(fMat[0][1], fMat[0][2], fMat[0][3],
116 fMat[1][1], fMat[1][2], fMat[1][3],
117 fMat[3][1], fMat[3][2], fMat[3][3]) -
118 fMat[3][0] * det3x3(fMat[0][1], fMat[0][2], fMat[0][3],
119 fMat[1][1], fMat[1][2], fMat[1][3],
120 fMat[2][1], fMat[2][2], fMat[2][3]);
121}
122
123///////////////////////////////////////////////////////////////////////////////
124
125// just picked a small value. not sure how to pick the "right" one
126#define TOO_SMALL_FOR_DETERMINANT (1.e-8)
127
128static inline double dabs(double x) {
129 if (x < 0) {
130 x = -x;
131 }
132 return x;
133}
134
135bool SkMatrix44::invert(SkMatrix44* inverse) const {
136 double det = this->determinant();
137 if (dabs(det) < TOO_SMALL_FOR_DETERMINANT) {
138 return false;
139 }
140 if (NULL == inverse) {
141 return true;
142 }
143
144 // we explicitly promote to doubles to keep the intermediate values in
145 // higher precision (assuming SkMScalar isn't already a double)
146 double m00 = fMat[0][0];
147 double m01 = fMat[0][1];
148 double m02 = fMat[0][2];
149 double m03 = fMat[0][3];
150 double m10 = fMat[1][0];
151 double m11 = fMat[1][1];
152 double m12 = fMat[1][2];
153 double m13 = fMat[1][3];
154 double m20 = fMat[2][0];
155 double m21 = fMat[2][1];
156 double m22 = fMat[2][2];
157 double m23 = fMat[2][3];
158 double m30 = fMat[3][0];
159 double m31 = fMat[3][1];
160 double m32 = fMat[3][2];
161 double m33 = fMat[3][3];
162
163 double tmp[4][4];
164
165 tmp[0][0] = m12*m23*m31 - m13*m22*m31 + m13*m21*m32 - m11*m23*m32 - m12*m21*m33 + m11*m22*m33;
166 tmp[0][1] = m03*m22*m31 - m02*m23*m31 - m03*m21*m32 + m01*m23*m32 + m02*m21*m33 - m01*m22*m33;
167 tmp[0][2] = m02*m13*m31 - m03*m12*m31 + m03*m11*m32 - m01*m13*m32 - m02*m11*m33 + m01*m12*m33;
168 tmp[0][3] = m03*m12*m21 - m02*m13*m21 - m03*m11*m22 + m01*m13*m22 + m02*m11*m23 - m01*m12*m23;
169 tmp[1][0] = m13*m22*m30 - m12*m23*m30 - m13*m20*m32 + m10*m23*m32 + m12*m20*m33 - m10*m22*m33;
170 tmp[1][1] = m02*m23*m30 - m03*m22*m30 + m03*m20*m32 - m00*m23*m32 - m02*m20*m33 + m00*m22*m33;
171 tmp[1][2] = m03*m12*m30 - m02*m13*m30 - m03*m10*m32 + m00*m13*m32 + m02*m10*m33 - m00*m12*m33;
172 tmp[1][3] = m02*m13*m20 - m03*m12*m20 + m03*m10*m22 - m00*m13*m22 - m02*m10*m23 + m00*m12*m23;
173 tmp[2][0] = m11*m23*m30 - m13*m21*m30 + m13*m20*m31 - m10*m23*m31 - m11*m20*m33 + m10*m21*m33;
174 tmp[2][1] = m03*m21*m30 - m01*m23*m30 - m03*m20*m31 + m00*m23*m31 + m01*m20*m33 - m00*m21*m33;
175 tmp[2][2] = m01*m13*m30 - m03*m11*m30 + m03*m10*m31 - m00*m13*m31 - m01*m10*m33 + m00*m11*m33;
176 tmp[2][3] = m03*m11*m20 - m01*m13*m20 - m03*m10*m21 + m00*m13*m21 + m01*m10*m23 - m00*m11*m23;
177 tmp[3][0] = m12*m21*m30 - m11*m22*m30 - m12*m20*m31 + m10*m22*m31 + m11*m20*m32 - m10*m21*m32;
178 tmp[3][1] = m01*m22*m30 - m02*m21*m30 + m02*m20*m31 - m00*m22*m31 - m01*m20*m32 + m00*m21*m32;
179 tmp[3][2] = m02*m11*m30 - m01*m12*m30 - m02*m10*m31 + m00*m12*m31 + m01*m10*m32 - m00*m11*m32;
180 tmp[3][3] = m01*m12*m20 - m02*m11*m20 + m02*m10*m21 - m00*m12*m21 - m01*m10*m22 + m00*m11*m22;
181
182 double invDet = 1.0 / det;
183 for (int i = 0; i < 4; i++) {
184 for (int j = 0; j < 4; j++) {
185 inverse->fMat[i][j] = SkDoubleToMScalar(tmp[i][j] * invDet);
186 }
187 }
188 return true;
189}
190
191///////////////////////////////////////////////////////////////////////////////
192
193void SkMatrix44::map(const SkScalar src[4], SkScalar dst[4]) const {
194 SkScalar result[4];
195 for (int i = 0; i < 4; i++) {
196 SkMScalar value = 0;
197 for (int j = 0; j < 4; j++) {
198 value += fMat[j][i] * src[j];
199 }
200 result[i] = value;
201 }
202 memcpy(dst, result, sizeof(result));
203}
204
205///////////////////////////////////////////////////////////////////////////////
206
207void SkMatrix44::dump() const {
208 SkDebugf("[%g %g %g %g][%g %g %g %g][%g %g %g %g][%g %g %g %g]\n",
reed@android.comc8c49c52010-02-24 15:36:57 +0000209#if 0
reed@android.com6d342a42010-02-23 20:18:17 +0000210 fMat[0][0], fMat[0][1], fMat[0][2], fMat[0][3],
211 fMat[1][0], fMat[1][1], fMat[1][2], fMat[1][3],
212 fMat[2][0], fMat[2][1], fMat[2][2], fMat[2][3],
213 fMat[3][0], fMat[3][1], fMat[3][2], fMat[3][3]);
reed@android.comc8c49c52010-02-24 15:36:57 +0000214#else
215 fMat[0][0], fMat[1][0], fMat[2][0], fMat[3][0],
216 fMat[0][1], fMat[1][1], fMat[2][1], fMat[3][1],
217 fMat[0][2], fMat[1][2], fMat[2][2], fMat[3][2],
218 fMat[0][3], fMat[1][3], fMat[2][3], fMat[3][3]);
219#endif
reed@android.com6d342a42010-02-23 20:18:17 +0000220}
221
222