blob: a57f9b117a9e113f3b1fe46cc871d64543369758 [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001
reed@google.com8260a892011-06-13 14:02:52 +00002/*
epoger@google.comec3ed6a2011-07-28 14:26:00 +00003 * Copyright 2011 Google Inc.
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
reed@google.com8260a892011-06-13 14:02:52 +00007 */
8
9
epoger@google.comec3ed6a2011-07-28 14:26:00 +000010
reed@google.com8260a892011-06-13 14:02:52 +000011#include "SkMatrix44.h"
12
13SkMatrix44::SkMatrix44() {
14 this->setIdentity();
15}
16
17SkMatrix44::SkMatrix44(const SkMatrix44& src) {
18 memcpy(this, &src, sizeof(src));
19}
20
21SkMatrix44::SkMatrix44(const SkMatrix44& a, const SkMatrix44& b) {
22 this->setConcat(a, b);
23}
24
25SkMScalar SkMatrix44::get(int row, int col) const {
26 SkASSERT(row <= 3 && row >= 0);
27 SkASSERT(col <= 3 && col >= 0);
28 return fMat[col][row];
29}
30
31void SkMatrix44::set(int row, int col, const SkMScalar& value) {
32 SkASSERT(row <= 3 && row >= 0);
33 SkASSERT(col <= 3 && col >= 0);
34 fMat[col][row] = value;
35}
36
37///////////////////////////////////////////////////////////////////////////////
38
reed@google.comda9fac02011-06-13 14:46:52 +000039void SkMatrix44::asColMajorf(float dst[]) const {
40 const SkMScalar* src = &fMat[0][0];
41#ifdef SK_MSCALAR_IS_DOUBLE
42 for (int i = 0; i < 16; ++i) {
43 dst[i] = SkMScalarToFloat(src[i]);
44 }
45#else
46 memcpy(dst, src, 16 * sizeof(float));
47#endif
48}
49
50void SkMatrix44::asColMajord(double dst[]) const {
51 const SkMScalar* src = &fMat[0][0];
52#ifdef SK_MSCALAR_IS_DOUBLE
53 memcpy(dst, src, 16 * sizeof(double));
54#else
55 for (int i = 0; i < 16; ++i) {
56 dst[i] = SkMScalarToDouble(src[i]);
57 }
58#endif
59}
60
61void SkMatrix44::asRowMajorf(float dst[]) const {
62 const SkMScalar* src = &fMat[0][0];
63 for (int i = 0; i < 4; ++i) {
64 dst[0] = SkMScalarToFloat(src[0]);
65 dst[4] = SkMScalarToFloat(src[1]);
66 dst[8] = SkMScalarToFloat(src[2]);
67 dst[12] = SkMScalarToFloat(src[3]);
68 src += 4;
69 dst += 1;
70 }
71}
72
73void SkMatrix44::asRowMajord(double dst[]) const {
74 const SkMScalar* src = &fMat[0][0];
75 for (int i = 0; i < 4; ++i) {
76 dst[0] = SkMScalarToDouble(src[0]);
77 dst[4] = SkMScalarToDouble(src[1]);
78 dst[8] = SkMScalarToDouble(src[2]);
79 dst[12] = SkMScalarToDouble(src[3]);
80 src += 4;
81 dst += 1;
82 }
83}
84
85///////////////////////////////////////////////////////////////////////////////
86
reed@google.com8260a892011-06-13 14:02:52 +000087static const SkMatrix44 gIdentity44;
88
89bool SkMatrix44::isIdentity() const {
90 return *this == gIdentity44;
91}
92
93///////////////////////////////////////////////////////////////////////////////
94
95void SkMatrix44::setIdentity() {
96 sk_bzero(fMat, sizeof(fMat));
97 fMat[0][0] = fMat[1][1] = fMat[2][2] = fMat[3][3] = 1;
98}
99
100void SkMatrix44::set3x3(SkMScalar m00, SkMScalar m01, SkMScalar m02,
101 SkMScalar m10, SkMScalar m11, SkMScalar m12,
102 SkMScalar m20, SkMScalar m21, SkMScalar m22) {
103 sk_bzero(fMat, sizeof(fMat));
104 fMat[0][0] = m00; fMat[0][1] = m01; fMat[0][2] = m02; fMat[0][3] = 0;
105 fMat[1][0] = m10; fMat[1][1] = m11; fMat[1][2] = m12; fMat[1][3] = 0;
106 fMat[2][0] = m20; fMat[2][1] = m21; fMat[2][2] = m22; fMat[2][3] = 0;
107 fMat[3][0] = 0; fMat[3][1] = 0; fMat[3][2] = 0; fMat[3][3] = 1;
108}
109
110///////////////////////////////////////////////////////////////////////////////
111
112void SkMatrix44::setTranslate(SkMScalar tx, SkMScalar ty, SkMScalar tz) {
113 this->setIdentity();
114 fMat[3][0] = tx;
115 fMat[3][1] = ty;
116 fMat[3][2] = tz;
117 fMat[3][3] = 1;
118}
119
120void SkMatrix44::preTranslate(SkMScalar dx, SkMScalar dy, SkMScalar dz) {
121 SkMatrix44 mat;
122 mat.setTranslate(dx, dy, dz);
123 this->preConcat(mat);
124}
125
126void SkMatrix44::postTranslate(SkMScalar dx, SkMScalar dy, SkMScalar dz) {
127 fMat[3][0] += dx;
128 fMat[3][1] += dy;
129 fMat[3][2] += dz;
130}
131
132///////////////////////////////////////////////////////////////////////////////
133
134void SkMatrix44::setScale(SkMScalar sx, SkMScalar sy, SkMScalar sz) {
135 sk_bzero(fMat, sizeof(fMat));
136 fMat[0][0] = sx;
137 fMat[1][1] = sy;
138 fMat[2][2] = sz;
139 fMat[3][3] = 1;
140}
141
142void SkMatrix44::preScale(SkMScalar sx, SkMScalar sy, SkMScalar sz) {
143 SkMatrix44 tmp;
144 tmp.setScale(sx, sy, sz);
145 this->preConcat(tmp);
146}
147
148void SkMatrix44::postScale(SkMScalar sx, SkMScalar sy, SkMScalar sz) {
149 for (int i = 0; i < 4; i++) {
150 fMat[i][0] *= sx;
151 fMat[i][1] *= sy;
152 fMat[i][2] *= sz;
153 }
154}
155
156///////////////////////////////////////////////////////////////////////////////
157
158void SkMatrix44::setRotateAbout(SkMScalar x, SkMScalar y, SkMScalar z,
159 SkMScalar radians) {
160 double len2 = x * x + y * y + z * z;
161 if (len2 != 1) {
162 if (len2 == 0) {
163 this->setIdentity();
164 return;
165 }
166 double scale = 1 / sqrt(len2);
167 x *= scale;
168 y *= scale;
169 z *= scale;
170 }
171 this->setRotateAboutUnit(x, y, z, radians);
172}
173
174void SkMatrix44::setRotateAboutUnit(SkMScalar x, SkMScalar y, SkMScalar z,
175 SkMScalar radians) {
176 double c = cos(radians);
177 double s = sin(radians);
178 double C = 1 - c;
179 double xs = x * s;
180 double ys = y * s;
181 double zs = z * s;
182 double xC = x * C;
183 double yC = y * C;
184 double zC = z * C;
185 double xyC = x * yC;
186 double yzC = y * zC;
187 double zxC = z * xC;
188
189 // if you're looking at wikipedia, remember that we're column major.
190 this->set3x3(x * xC + c, xyC + zs, zxC - ys,
191 xyC - zs, y * yC + c, yzC + xs,
192 zxC + ys, yzC - xs, z * zC + c);
193}
194
195///////////////////////////////////////////////////////////////////////////////
196
197void SkMatrix44::setConcat(const SkMatrix44& a, const SkMatrix44& b) {
198 SkMScalar result[4][4];
199 for (int i = 0; i < 4; i++) {
200 for (int j = 0; j < 4; j++) {
201 double value = 0;
202 for (int k = 0; k < 4; k++) {
203 value += SkMScalarToDouble(a.fMat[k][i]) * b.fMat[j][k];
204 }
205 result[j][i] = SkDoubleToMScalar(value);
206 }
207 }
208 memcpy(fMat, result, sizeof(result));
209}
210
211///////////////////////////////////////////////////////////////////////////////
212
213static inline SkMScalar det2x2(double m00, double m01, double m10, double m11) {
214 return m00 * m11 - m10 * m01;
215}
216
217static inline double det3x3(double m00, double m01, double m02,
218 double m10, double m11, double m12,
219 double m20, double m21, double m22) {
220 return m00 * det2x2(m11, m12, m21, m22) -
221 m10 * det2x2(m01, m02, m21, m22) +
222 m20 * det2x2(m01, m02, m11, m12);
223}
224
225/** We always perform the calculation in doubles, to avoid prematurely losing
226 precision along the way. This relies on the compiler automatically
227 promoting our SkMScalar values to double (if needed).
228 */
229double SkMatrix44::determinant() const {
230 return fMat[0][0] * det3x3(fMat[1][1], fMat[1][2], fMat[1][3],
231 fMat[2][1], fMat[2][2], fMat[2][3],
232 fMat[3][1], fMat[3][2], fMat[3][3]) -
233 fMat[1][0] * det3x3(fMat[0][1], fMat[0][2], fMat[0][3],
234 fMat[2][1], fMat[2][2], fMat[2][3],
235 fMat[3][1], fMat[3][2], fMat[3][3]) +
236 fMat[2][0] * det3x3(fMat[0][1], fMat[0][2], fMat[0][3],
237 fMat[1][1], fMat[1][2], fMat[1][3],
238 fMat[3][1], fMat[3][2], fMat[3][3]) -
239 fMat[3][0] * det3x3(fMat[0][1], fMat[0][2], fMat[0][3],
240 fMat[1][1], fMat[1][2], fMat[1][3],
241 fMat[2][1], fMat[2][2], fMat[2][3]);
242}
243
244///////////////////////////////////////////////////////////////////////////////
245
246// just picked a small value. not sure how to pick the "right" one
247#define TOO_SMALL_FOR_DETERMINANT (1.e-8)
248
249static inline double dabs(double x) {
250 if (x < 0) {
251 x = -x;
252 }
253 return x;
254}
255
256bool SkMatrix44::invert(SkMatrix44* inverse) const {
257 double det = this->determinant();
258 if (dabs(det) < TOO_SMALL_FOR_DETERMINANT) {
259 return false;
260 }
261 if (NULL == inverse) {
262 return true;
263 }
264
265 // we explicitly promote to doubles to keep the intermediate values in
266 // higher precision (assuming SkMScalar isn't already a double)
267 double m00 = fMat[0][0];
268 double m01 = fMat[0][1];
269 double m02 = fMat[0][2];
270 double m03 = fMat[0][3];
271 double m10 = fMat[1][0];
272 double m11 = fMat[1][1];
273 double m12 = fMat[1][2];
274 double m13 = fMat[1][3];
275 double m20 = fMat[2][0];
276 double m21 = fMat[2][1];
277 double m22 = fMat[2][2];
278 double m23 = fMat[2][3];
279 double m30 = fMat[3][0];
280 double m31 = fMat[3][1];
281 double m32 = fMat[3][2];
282 double m33 = fMat[3][3];
283
284 double tmp[4][4];
285
286 tmp[0][0] = m12*m23*m31 - m13*m22*m31 + m13*m21*m32 - m11*m23*m32 - m12*m21*m33 + m11*m22*m33;
287 tmp[0][1] = m03*m22*m31 - m02*m23*m31 - m03*m21*m32 + m01*m23*m32 + m02*m21*m33 - m01*m22*m33;
288 tmp[0][2] = m02*m13*m31 - m03*m12*m31 + m03*m11*m32 - m01*m13*m32 - m02*m11*m33 + m01*m12*m33;
289 tmp[0][3] = m03*m12*m21 - m02*m13*m21 - m03*m11*m22 + m01*m13*m22 + m02*m11*m23 - m01*m12*m23;
290 tmp[1][0] = m13*m22*m30 - m12*m23*m30 - m13*m20*m32 + m10*m23*m32 + m12*m20*m33 - m10*m22*m33;
291 tmp[1][1] = m02*m23*m30 - m03*m22*m30 + m03*m20*m32 - m00*m23*m32 - m02*m20*m33 + m00*m22*m33;
292 tmp[1][2] = m03*m12*m30 - m02*m13*m30 - m03*m10*m32 + m00*m13*m32 + m02*m10*m33 - m00*m12*m33;
293 tmp[1][3] = m02*m13*m20 - m03*m12*m20 + m03*m10*m22 - m00*m13*m22 - m02*m10*m23 + m00*m12*m23;
294 tmp[2][0] = m11*m23*m30 - m13*m21*m30 + m13*m20*m31 - m10*m23*m31 - m11*m20*m33 + m10*m21*m33;
295 tmp[2][1] = m03*m21*m30 - m01*m23*m30 - m03*m20*m31 + m00*m23*m31 + m01*m20*m33 - m00*m21*m33;
296 tmp[2][2] = m01*m13*m30 - m03*m11*m30 + m03*m10*m31 - m00*m13*m31 - m01*m10*m33 + m00*m11*m33;
297 tmp[2][3] = m03*m11*m20 - m01*m13*m20 - m03*m10*m21 + m00*m13*m21 + m01*m10*m23 - m00*m11*m23;
298 tmp[3][0] = m12*m21*m30 - m11*m22*m30 - m12*m20*m31 + m10*m22*m31 + m11*m20*m32 - m10*m21*m32;
299 tmp[3][1] = m01*m22*m30 - m02*m21*m30 + m02*m20*m31 - m00*m22*m31 - m01*m20*m32 + m00*m21*m32;
300 tmp[3][2] = m02*m11*m30 - m01*m12*m30 - m02*m10*m31 + m00*m12*m31 + m01*m10*m32 - m00*m11*m32;
301 tmp[3][3] = m01*m12*m20 - m02*m11*m20 + m02*m10*m21 - m00*m12*m21 - m01*m10*m22 + m00*m11*m22;
302
303 double invDet = 1.0 / det;
304 for (int i = 0; i < 4; i++) {
305 for (int j = 0; j < 4; j++) {
306 inverse->fMat[i][j] = SkDoubleToMScalar(tmp[i][j] * invDet);
307 }
308 }
309 return true;
310}
311
312///////////////////////////////////////////////////////////////////////////////
313
314void SkMatrix44::map(const SkScalar src[4], SkScalar dst[4]) const {
315 SkScalar result[4];
316 for (int i = 0; i < 4; i++) {
317 SkMScalar value = 0;
318 for (int j = 0; j < 4; j++) {
319 value += fMat[j][i] * src[j];
320 }
321 result[i] = value;
322 }
323 memcpy(dst, result, sizeof(result));
324}
325
326///////////////////////////////////////////////////////////////////////////////
327
328void SkMatrix44::dump() const {
tomhudson@google.com9ac4a892011-06-28 13:53:13 +0000329 static const char* format =
330 "[%g %g %g %g][%g %g %g %g][%g %g %g %g][%g %g %g %g]\n";
reed@google.com8260a892011-06-13 14:02:52 +0000331#if 0
tomhudson@google.com9ac4a892011-06-28 13:53:13 +0000332 SkDebugf(format,
reed@google.com8260a892011-06-13 14:02:52 +0000333 fMat[0][0], fMat[1][0], fMat[2][0], fMat[3][0],
334 fMat[0][1], fMat[1][1], fMat[2][1], fMat[3][1],
335 fMat[0][2], fMat[1][2], fMat[2][2], fMat[3][2],
336 fMat[0][3], fMat[1][3], fMat[2][3], fMat[3][3]);
tomhudson@google.com9ac4a892011-06-28 13:53:13 +0000337#else
338 SkDebugf(format,
339 fMat[0][0], fMat[0][1], fMat[0][2], fMat[0][3],
340 fMat[1][0], fMat[1][1], fMat[1][2], fMat[1][3],
341 fMat[2][0], fMat[2][1], fMat[2][2], fMat[2][3],
342 fMat[3][0], fMat[3][1], fMat[3][2], fMat[3][3]);
reed@google.com8260a892011-06-13 14:02:52 +0000343#endif
344}
345
346///////////////////////////////////////////////////////////////////////////////
347
348static void initFromMatrix(SkMScalar dst[4][4], const SkMatrix& src) {
349 sk_bzero(dst, 16 * sizeof(SkMScalar));
350 dst[0][0] = src[SkMatrix::kMScaleX];
351 dst[1][0] = src[SkMatrix::kMSkewX];
352 dst[3][0] = src[SkMatrix::kMTransX];
353 dst[0][1] = src[SkMatrix::kMSkewY];
354 dst[1][1] = src[SkMatrix::kMScaleY];
355 dst[3][1] = src[SkMatrix::kMTransY];
356 dst[2][2] = dst[3][3] = 1;
357}
358
359SkMatrix44::SkMatrix44(const SkMatrix& src) {
360 initFromMatrix(fMat, src);
361}
362
363SkMatrix44& SkMatrix44::operator=(const SkMatrix& src) {
364 initFromMatrix(fMat, src);
365 return *this;
366}
367
368SkMatrix44::operator SkMatrix() const {
369 SkMatrix dst;
370 dst.reset(); // setup our perspective correctly for identity
371
372 dst[SkMatrix::kMScaleX] = SkMScalarToFloat(fMat[0][0]);
373 dst[SkMatrix::kMSkewX] = SkMScalarToFloat(fMat[1][0]);
374 dst[SkMatrix::kMTransX] = SkMScalarToFloat(fMat[3][0]);
375
376 dst[SkMatrix::kMSkewY] = SkMScalarToFloat(fMat[0][1]);
377 dst[SkMatrix::kMScaleY] = SkMScalarToFloat(fMat[1][1]);
378 dst[SkMatrix::kMTransY] = SkMScalarToFloat(fMat[3][1]);
379
380 return dst;
381}