blob: 841eec27d1a3b47f73d4411259d47a92a2d6f267 [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));
reed@android.com38203fb2010-02-26 21:45:49 +000027 fMat[0][0] = fMat[1][1] = fMat[2][2] = fMat[3][3] = 1;
reed@android.com6d342a42010-02-23 20:18:17 +000028}
29
reed@android.com38203fb2010-02-26 21:45:49 +000030void SkMatrix44::set3x3(SkMScalar m00, SkMScalar m01, SkMScalar m02,
31 SkMScalar m10, SkMScalar m11, SkMScalar m12,
32 SkMScalar m20, SkMScalar m21, SkMScalar m22) {
33 sk_bzero(fMat, sizeof(fMat));
34 fMat[0][0] = m00; fMat[0][1] = m01; fMat[0][2] = m02; fMat[0][3] = 0;
35 fMat[1][0] = m10; fMat[1][1] = m11; fMat[1][2] = m12; fMat[1][3] = 0;
36 fMat[2][0] = m20; fMat[2][1] = m21; fMat[2][2] = m22; fMat[2][3] = 0;
37 fMat[3][0] = 0; fMat[3][1] = 0; fMat[3][2] = 0; fMat[3][3] = 1;
38}
39
40///////////////////////////////////////////////////////////////////////////////
41
reed@android.com6d342a42010-02-23 20:18:17 +000042void SkMatrix44::setTranslate(SkMScalar tx, SkMScalar ty, SkMScalar tz) {
reed@android.comc8c49c52010-02-24 15:36:57 +000043 this->setIdentity();
reed@android.com6d342a42010-02-23 20:18:17 +000044 fMat[3][0] = tx;
45 fMat[3][1] = ty;
46 fMat[3][2] = tz;
reed@android.com38203fb2010-02-26 21:45:49 +000047 fMat[3][3] = 1;
reed@android.com6d342a42010-02-23 20:18:17 +000048}
49
50void SkMatrix44::preTranslate(SkMScalar dx, SkMScalar dy, SkMScalar dz) {
51 SkMatrix44 mat;
52 mat.setTranslate(dx, dy, dz);
53 this->preConcat(mat);
54}
55
56void SkMatrix44::postTranslate(SkMScalar dx, SkMScalar dy, SkMScalar dz) {
57 fMat[3][0] += dx;
58 fMat[3][1] += dy;
59 fMat[3][2] += dz;
60}
61
62///////////////////////////////////////////////////////////////////////////////
63
64void SkMatrix44::setScale(SkMScalar sx, SkMScalar sy, SkMScalar sz) {
65 sk_bzero(fMat, sizeof(fMat));
66 fMat[0][0] = sx;
67 fMat[1][1] = sy;
68 fMat[2][2] = sz;
reed@android.com38203fb2010-02-26 21:45:49 +000069 fMat[3][3] = 1;
reed@android.com6d342a42010-02-23 20:18:17 +000070}
71
72void SkMatrix44::preScale(SkMScalar sx, SkMScalar sy, SkMScalar sz) {
73 SkMatrix44 tmp;
74 tmp.setScale(sx, sy, sz);
75 this->preConcat(tmp);
76}
77
78void SkMatrix44::postScale(SkMScalar sx, SkMScalar sy, SkMScalar sz) {
79 for (int i = 0; i < 4; i++) {
80 fMat[i][0] *= sx;
81 fMat[i][1] *= sy;
82 fMat[i][2] *= sz;
83 }
84}
85
86///////////////////////////////////////////////////////////////////////////////
87
reed@android.com38203fb2010-02-26 21:45:49 +000088void SkMatrix44::setRotateAbout(SkMScalar x, SkMScalar y, SkMScalar z,
89 SkMScalar radians) {
90 double len2 = x * x + y * y + z * z;
91 if (len2 != 1) {
92 if (len2 == 0) {
93 this->setIdentity();
94 return;
95 }
96 double scale = 1 / sqrt(len2);
97 x *= scale;
98 y *= scale;
99 z *= scale;
100 }
101 this->setRotateAboutUnit(x, y, z, radians);
102}
103
104void SkMatrix44::setRotateAboutUnit(SkMScalar x, SkMScalar y, SkMScalar z,
105 SkMScalar radians) {
106 double c = cos(radians);
107 double s = sin(radians);
108 double C = 1 - c;
109 double xs = x * s;
110 double ys = y * s;
111 double zs = z * s;
112 double xC = x * C;
113 double yC = y * C;
114 double zC = z * C;
115 double xyC = x * yC;
116 double yzC = y * zC;
117 double zxC = z * xC;
118
119 this->set3x3(x * xC + c, xyC - zs, zxC + ys,
120 xyC + zs, y * yC + c, yzC - xs,
121 zxC - ys, yzC + xs, z * zC + c);
122}
123
124///////////////////////////////////////////////////////////////////////////////
125
reed@android.com6d342a42010-02-23 20:18:17 +0000126void SkMatrix44::setConcat(const SkMatrix44& a, const SkMatrix44& b) {
127 SkMScalar result[4][4];
128 for (int i = 0; i < 4; i++) {
129 for (int j = 0; j < 4; j++) {
130 double value = 0;
131 for (int k = 0; k < 4; k++) {
reed@android.comc8c49c52010-02-24 15:36:57 +0000132 value += SkMScalarToDouble(a.fMat[k][i]) * b.fMat[j][k];
reed@android.com6d342a42010-02-23 20:18:17 +0000133 }
134 result[j][i] = SkDoubleToMScalar(value);
135 }
136 }
137 memcpy(fMat, result, sizeof(result));
138}
139
140///////////////////////////////////////////////////////////////////////////////
141
142static inline SkMScalar det2x2(double m00, double m01, double m10, double m11) {
143 return m00 * m11 - m10 * m01;
144}
145
146static inline double det3x3(double m00, double m01, double m02,
147 double m10, double m11, double m12,
148 double m20, double m21, double m22) {
149 return m00 * det2x2(m11, m12, m21, m22) -
150 m10 * det2x2(m01, m02, m21, m22) +
151 m20 * det2x2(m01, m02, m11, m12);
152}
153
154/** We always perform the calculation in doubles, to avoid prematurely losing
155 precision along the way. This relies on the compiler automatically
156 promoting our SkMScalar values to double (if needed).
157 */
158double SkMatrix44::determinant() const {
159 return fMat[0][0] * det3x3(fMat[1][1], fMat[1][2], fMat[1][3],
160 fMat[2][1], fMat[2][2], fMat[2][3],
161 fMat[3][1], fMat[3][2], fMat[3][3]) -
162 fMat[1][0] * det3x3(fMat[0][1], fMat[0][2], fMat[0][3],
163 fMat[2][1], fMat[2][2], fMat[2][3],
164 fMat[3][1], fMat[3][2], fMat[3][3]) +
165 fMat[2][0] * det3x3(fMat[0][1], fMat[0][2], fMat[0][3],
166 fMat[1][1], fMat[1][2], fMat[1][3],
167 fMat[3][1], fMat[3][2], fMat[3][3]) -
168 fMat[3][0] * det3x3(fMat[0][1], fMat[0][2], fMat[0][3],
169 fMat[1][1], fMat[1][2], fMat[1][3],
170 fMat[2][1], fMat[2][2], fMat[2][3]);
171}
172
173///////////////////////////////////////////////////////////////////////////////
174
175// just picked a small value. not sure how to pick the "right" one
176#define TOO_SMALL_FOR_DETERMINANT (1.e-8)
177
178static inline double dabs(double x) {
179 if (x < 0) {
180 x = -x;
181 }
182 return x;
183}
184
185bool SkMatrix44::invert(SkMatrix44* inverse) const {
186 double det = this->determinant();
187 if (dabs(det) < TOO_SMALL_FOR_DETERMINANT) {
188 return false;
189 }
190 if (NULL == inverse) {
191 return true;
192 }
193
194 // we explicitly promote to doubles to keep the intermediate values in
195 // higher precision (assuming SkMScalar isn't already a double)
196 double m00 = fMat[0][0];
197 double m01 = fMat[0][1];
198 double m02 = fMat[0][2];
199 double m03 = fMat[0][3];
200 double m10 = fMat[1][0];
201 double m11 = fMat[1][1];
202 double m12 = fMat[1][2];
203 double m13 = fMat[1][3];
204 double m20 = fMat[2][0];
205 double m21 = fMat[2][1];
206 double m22 = fMat[2][2];
207 double m23 = fMat[2][3];
208 double m30 = fMat[3][0];
209 double m31 = fMat[3][1];
210 double m32 = fMat[3][2];
211 double m33 = fMat[3][3];
212
213 double tmp[4][4];
214
215 tmp[0][0] = m12*m23*m31 - m13*m22*m31 + m13*m21*m32 - m11*m23*m32 - m12*m21*m33 + m11*m22*m33;
216 tmp[0][1] = m03*m22*m31 - m02*m23*m31 - m03*m21*m32 + m01*m23*m32 + m02*m21*m33 - m01*m22*m33;
217 tmp[0][2] = m02*m13*m31 - m03*m12*m31 + m03*m11*m32 - m01*m13*m32 - m02*m11*m33 + m01*m12*m33;
218 tmp[0][3] = m03*m12*m21 - m02*m13*m21 - m03*m11*m22 + m01*m13*m22 + m02*m11*m23 - m01*m12*m23;
219 tmp[1][0] = m13*m22*m30 - m12*m23*m30 - m13*m20*m32 + m10*m23*m32 + m12*m20*m33 - m10*m22*m33;
220 tmp[1][1] = m02*m23*m30 - m03*m22*m30 + m03*m20*m32 - m00*m23*m32 - m02*m20*m33 + m00*m22*m33;
221 tmp[1][2] = m03*m12*m30 - m02*m13*m30 - m03*m10*m32 + m00*m13*m32 + m02*m10*m33 - m00*m12*m33;
222 tmp[1][3] = m02*m13*m20 - m03*m12*m20 + m03*m10*m22 - m00*m13*m22 - m02*m10*m23 + m00*m12*m23;
223 tmp[2][0] = m11*m23*m30 - m13*m21*m30 + m13*m20*m31 - m10*m23*m31 - m11*m20*m33 + m10*m21*m33;
224 tmp[2][1] = m03*m21*m30 - m01*m23*m30 - m03*m20*m31 + m00*m23*m31 + m01*m20*m33 - m00*m21*m33;
225 tmp[2][2] = m01*m13*m30 - m03*m11*m30 + m03*m10*m31 - m00*m13*m31 - m01*m10*m33 + m00*m11*m33;
226 tmp[2][3] = m03*m11*m20 - m01*m13*m20 - m03*m10*m21 + m00*m13*m21 + m01*m10*m23 - m00*m11*m23;
227 tmp[3][0] = m12*m21*m30 - m11*m22*m30 - m12*m20*m31 + m10*m22*m31 + m11*m20*m32 - m10*m21*m32;
228 tmp[3][1] = m01*m22*m30 - m02*m21*m30 + m02*m20*m31 - m00*m22*m31 - m01*m20*m32 + m00*m21*m32;
229 tmp[3][2] = m02*m11*m30 - m01*m12*m30 - m02*m10*m31 + m00*m12*m31 + m01*m10*m32 - m00*m11*m32;
230 tmp[3][3] = m01*m12*m20 - m02*m11*m20 + m02*m10*m21 - m00*m12*m21 - m01*m10*m22 + m00*m11*m22;
231
232 double invDet = 1.0 / det;
233 for (int i = 0; i < 4; i++) {
234 for (int j = 0; j < 4; j++) {
235 inverse->fMat[i][j] = SkDoubleToMScalar(tmp[i][j] * invDet);
236 }
237 }
238 return true;
239}
240
241///////////////////////////////////////////////////////////////////////////////
242
243void SkMatrix44::map(const SkScalar src[4], SkScalar dst[4]) const {
244 SkScalar result[4];
245 for (int i = 0; i < 4; i++) {
246 SkMScalar value = 0;
247 for (int j = 0; j < 4; j++) {
248 value += fMat[j][i] * src[j];
249 }
250 result[i] = value;
251 }
252 memcpy(dst, result, sizeof(result));
253}
254
255///////////////////////////////////////////////////////////////////////////////
256
257void SkMatrix44::dump() const {
258 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 +0000259#if 0
reed@android.com6d342a42010-02-23 20:18:17 +0000260 fMat[0][0], fMat[0][1], fMat[0][2], fMat[0][3],
261 fMat[1][0], fMat[1][1], fMat[1][2], fMat[1][3],
262 fMat[2][0], fMat[2][1], fMat[2][2], fMat[2][3],
263 fMat[3][0], fMat[3][1], fMat[3][2], fMat[3][3]);
reed@android.comc8c49c52010-02-24 15:36:57 +0000264#else
265 fMat[0][0], fMat[1][0], fMat[2][0], fMat[3][0],
266 fMat[0][1], fMat[1][1], fMat[2][1], fMat[3][1],
267 fMat[0][2], fMat[1][2], fMat[2][2], fMat[3][2],
268 fMat[0][3], fMat[1][3], fMat[2][3], fMat[3][3]);
269#endif
reed@android.com6d342a42010-02-23 20:18:17 +0000270}
271
reed@android.comd055c1f2010-03-01 14:54:05 +0000272///////////////////////////////////////////////////////////////////////////////
273
274static void initFromMatrix(SkMScalar dst[4][4], const SkMatrix& src) {
275 sk_bzero(dst, 16 * sizeof(SkMScalar));
276 dst[0][0] = src[SkMatrix::kMScaleX];
277 dst[1][0] = src[SkMatrix::kMSkewX];
278 dst[3][0] = src[SkMatrix::kMTransX];
279 dst[0][1] = src[SkMatrix::kMSkewY];
280 dst[1][1] = src[SkMatrix::kMScaleY];
281 dst[3][1] = src[SkMatrix::kMTransY];
282 dst[2][2] = dst[3][3] = 1;
283}
284
285SkMatrix44::SkMatrix44(const SkMatrix& src) {
286 initFromMatrix(fMat, src);
287}
288
289SkMatrix44& SkMatrix44::operator=(const SkMatrix& src) {
290 initFromMatrix(fMat, src);
291 return *this;
292}
293
294SkMatrix44::operator SkMatrix() const {
295 SkMatrix dst;
296 dst.reset(); // setup our perspective correctly for identity
297
298 dst[SkMatrix::kMScaleX] = SkMScalarToFloat(fMat[0][0]);
299 dst[SkMatrix::kMSkewX] = SkMScalarToFloat(fMat[1][0]);
300 dst[SkMatrix::kMTransX] = SkMScalarToFloat(fMat[3][0]);
301
302 dst[SkMatrix::kMSkewY] = SkMScalarToFloat(fMat[0][1]);
303 dst[SkMatrix::kMScaleY] = SkMScalarToFloat(fMat[1][1]);
304 dst[SkMatrix::kMTransY] = SkMScalarToFloat(fMat[3][1]);
305
306 return dst;
307}
308
309
reed@android.com6d342a42010-02-23 20:18:17 +0000310