blob: a59c91b60da25feab25ac494eead98be2edc6e0b [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);
bsalomon@google.com9d12f5c2011-09-29 18:08:18 +0000167 x = SkDoubleToMScalar(x * scale);
168 y = SkDoubleToMScalar(y * scale);
169 z = SkDoubleToMScalar(z * scale);
reed@google.com8260a892011-06-13 14:02:52 +0000170 }
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.
bsalomon@google.com9d12f5c2011-09-29 18:08:18 +0000190 this->set3x3(SkDoubleToMScalar(x * xC + c), // scale x
191 SkDoubleToMScalar(xyC + zs), // skew x
192 SkDoubleToMScalar(zxC - ys), // trans x
193
194 SkDoubleToMScalar(xyC - zs), // skew y
195 SkDoubleToMScalar(y * yC + c), // scale y
196 SkDoubleToMScalar(yzC + xs), // trans y
197
198 SkDoubleToMScalar(zxC + ys), // persp x
199 SkDoubleToMScalar(yzC - xs), // persp y
200 SkDoubleToMScalar(z * zC + c)); // persp 2
reed@google.com8260a892011-06-13 14:02:52 +0000201}
202
203///////////////////////////////////////////////////////////////////////////////
204
205void SkMatrix44::setConcat(const SkMatrix44& a, const SkMatrix44& b) {
206 SkMScalar result[4][4];
207 for (int i = 0; i < 4; i++) {
208 for (int j = 0; j < 4; j++) {
209 double value = 0;
210 for (int k = 0; k < 4; k++) {
211 value += SkMScalarToDouble(a.fMat[k][i]) * b.fMat[j][k];
212 }
213 result[j][i] = SkDoubleToMScalar(value);
214 }
215 }
216 memcpy(fMat, result, sizeof(result));
217}
218
219///////////////////////////////////////////////////////////////////////////////
220
221static inline SkMScalar det2x2(double m00, double m01, double m10, double m11) {
bsalomon@google.com9d12f5c2011-09-29 18:08:18 +0000222 return SkDoubleToMScalar(m00 * m11 - m10 * m01);
reed@google.com8260a892011-06-13 14:02:52 +0000223}
224
225static inline double det3x3(double m00, double m01, double m02,
226 double m10, double m11, double m12,
227 double m20, double m21, double m22) {
228 return m00 * det2x2(m11, m12, m21, m22) -
229 m10 * det2x2(m01, m02, m21, m22) +
230 m20 * det2x2(m01, m02, m11, m12);
231}
232
233/** We always perform the calculation in doubles, to avoid prematurely losing
234 precision along the way. This relies on the compiler automatically
235 promoting our SkMScalar values to double (if needed).
236 */
237double SkMatrix44::determinant() const {
238 return fMat[0][0] * det3x3(fMat[1][1], fMat[1][2], fMat[1][3],
239 fMat[2][1], fMat[2][2], fMat[2][3],
240 fMat[3][1], fMat[3][2], fMat[3][3]) -
241 fMat[1][0] * det3x3(fMat[0][1], fMat[0][2], fMat[0][3],
242 fMat[2][1], fMat[2][2], fMat[2][3],
243 fMat[3][1], fMat[3][2], fMat[3][3]) +
244 fMat[2][0] * det3x3(fMat[0][1], fMat[0][2], fMat[0][3],
245 fMat[1][1], fMat[1][2], fMat[1][3],
246 fMat[3][1], fMat[3][2], fMat[3][3]) -
247 fMat[3][0] * det3x3(fMat[0][1], fMat[0][2], fMat[0][3],
248 fMat[1][1], fMat[1][2], fMat[1][3],
249 fMat[2][1], fMat[2][2], fMat[2][3]);
250}
251
252///////////////////////////////////////////////////////////////////////////////
253
254// just picked a small value. not sure how to pick the "right" one
255#define TOO_SMALL_FOR_DETERMINANT (1.e-8)
256
257static inline double dabs(double x) {
258 if (x < 0) {
259 x = -x;
260 }
261 return x;
262}
263
264bool SkMatrix44::invert(SkMatrix44* inverse) const {
265 double det = this->determinant();
266 if (dabs(det) < TOO_SMALL_FOR_DETERMINANT) {
267 return false;
268 }
269 if (NULL == inverse) {
270 return true;
271 }
272
273 // we explicitly promote to doubles to keep the intermediate values in
274 // higher precision (assuming SkMScalar isn't already a double)
275 double m00 = fMat[0][0];
276 double m01 = fMat[0][1];
277 double m02 = fMat[0][2];
278 double m03 = fMat[0][3];
279 double m10 = fMat[1][0];
280 double m11 = fMat[1][1];
281 double m12 = fMat[1][2];
282 double m13 = fMat[1][3];
283 double m20 = fMat[2][0];
284 double m21 = fMat[2][1];
285 double m22 = fMat[2][2];
286 double m23 = fMat[2][3];
287 double m30 = fMat[3][0];
288 double m31 = fMat[3][1];
289 double m32 = fMat[3][2];
290 double m33 = fMat[3][3];
291
292 double tmp[4][4];
293
294 tmp[0][0] = m12*m23*m31 - m13*m22*m31 + m13*m21*m32 - m11*m23*m32 - m12*m21*m33 + m11*m22*m33;
295 tmp[0][1] = m03*m22*m31 - m02*m23*m31 - m03*m21*m32 + m01*m23*m32 + m02*m21*m33 - m01*m22*m33;
296 tmp[0][2] = m02*m13*m31 - m03*m12*m31 + m03*m11*m32 - m01*m13*m32 - m02*m11*m33 + m01*m12*m33;
297 tmp[0][3] = m03*m12*m21 - m02*m13*m21 - m03*m11*m22 + m01*m13*m22 + m02*m11*m23 - m01*m12*m23;
298 tmp[1][0] = m13*m22*m30 - m12*m23*m30 - m13*m20*m32 + m10*m23*m32 + m12*m20*m33 - m10*m22*m33;
299 tmp[1][1] = m02*m23*m30 - m03*m22*m30 + m03*m20*m32 - m00*m23*m32 - m02*m20*m33 + m00*m22*m33;
300 tmp[1][2] = m03*m12*m30 - m02*m13*m30 - m03*m10*m32 + m00*m13*m32 + m02*m10*m33 - m00*m12*m33;
301 tmp[1][3] = m02*m13*m20 - m03*m12*m20 + m03*m10*m22 - m00*m13*m22 - m02*m10*m23 + m00*m12*m23;
302 tmp[2][0] = m11*m23*m30 - m13*m21*m30 + m13*m20*m31 - m10*m23*m31 - m11*m20*m33 + m10*m21*m33;
303 tmp[2][1] = m03*m21*m30 - m01*m23*m30 - m03*m20*m31 + m00*m23*m31 + m01*m20*m33 - m00*m21*m33;
304 tmp[2][2] = m01*m13*m30 - m03*m11*m30 + m03*m10*m31 - m00*m13*m31 - m01*m10*m33 + m00*m11*m33;
305 tmp[2][3] = m03*m11*m20 - m01*m13*m20 - m03*m10*m21 + m00*m13*m21 + m01*m10*m23 - m00*m11*m23;
306 tmp[3][0] = m12*m21*m30 - m11*m22*m30 - m12*m20*m31 + m10*m22*m31 + m11*m20*m32 - m10*m21*m32;
307 tmp[3][1] = m01*m22*m30 - m02*m21*m30 + m02*m20*m31 - m00*m22*m31 - m01*m20*m32 + m00*m21*m32;
308 tmp[3][2] = m02*m11*m30 - m01*m12*m30 - m02*m10*m31 + m00*m12*m31 + m01*m10*m32 - m00*m11*m32;
309 tmp[3][3] = m01*m12*m20 - m02*m11*m20 + m02*m10*m21 - m00*m12*m21 - m01*m10*m22 + m00*m11*m22;
310
311 double invDet = 1.0 / det;
312 for (int i = 0; i < 4; i++) {
313 for (int j = 0; j < 4; j++) {
314 inverse->fMat[i][j] = SkDoubleToMScalar(tmp[i][j] * invDet);
315 }
316 }
317 return true;
318}
319
320///////////////////////////////////////////////////////////////////////////////
321
322void SkMatrix44::map(const SkScalar src[4], SkScalar dst[4]) const {
323 SkScalar result[4];
324 for (int i = 0; i < 4; i++) {
325 SkMScalar value = 0;
326 for (int j = 0; j < 4; j++) {
327 value += fMat[j][i] * src[j];
328 }
bsalomon@google.com72e49b82011-10-27 21:47:03 +0000329 result[i] = SkMScalarToScalar(value);
reed@google.com8260a892011-06-13 14:02:52 +0000330 }
331 memcpy(dst, result, sizeof(result));
332}
333
334///////////////////////////////////////////////////////////////////////////////
335
336void SkMatrix44::dump() const {
tomhudson@google.com9ac4a892011-06-28 13:53:13 +0000337 static const char* format =
338 "[%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 +0000339#if 0
tomhudson@google.com9ac4a892011-06-28 13:53:13 +0000340 SkDebugf(format,
reed@google.com8260a892011-06-13 14:02:52 +0000341 fMat[0][0], fMat[1][0], fMat[2][0], fMat[3][0],
342 fMat[0][1], fMat[1][1], fMat[2][1], fMat[3][1],
343 fMat[0][2], fMat[1][2], fMat[2][2], fMat[3][2],
344 fMat[0][3], fMat[1][3], fMat[2][3], fMat[3][3]);
tomhudson@google.com9ac4a892011-06-28 13:53:13 +0000345#else
346 SkDebugf(format,
347 fMat[0][0], fMat[0][1], fMat[0][2], fMat[0][3],
348 fMat[1][0], fMat[1][1], fMat[1][2], fMat[1][3],
349 fMat[2][0], fMat[2][1], fMat[2][2], fMat[2][3],
350 fMat[3][0], fMat[3][1], fMat[3][2], fMat[3][3]);
reed@google.com8260a892011-06-13 14:02:52 +0000351#endif
352}
353
354///////////////////////////////////////////////////////////////////////////////
355
356static void initFromMatrix(SkMScalar dst[4][4], const SkMatrix& src) {
357 sk_bzero(dst, 16 * sizeof(SkMScalar));
bsalomon@google.com72e49b82011-10-27 21:47:03 +0000358 dst[0][0] = SkScalarToMScalar(src[SkMatrix::kMScaleX]);
359 dst[1][0] = SkScalarToMScalar(src[SkMatrix::kMSkewX]);
360 dst[3][0] = SkScalarToMScalar(src[SkMatrix::kMTransX]);
361 dst[0][1] = SkScalarToMScalar(src[SkMatrix::kMSkewY]);
362 dst[1][1] = SkScalarToMScalar(src[SkMatrix::kMScaleY]);
363 dst[3][1] = SkScalarToMScalar(src[SkMatrix::kMTransY]);
reed@google.com8260a892011-06-13 14:02:52 +0000364 dst[2][2] = dst[3][3] = 1;
365}
366
367SkMatrix44::SkMatrix44(const SkMatrix& src) {
368 initFromMatrix(fMat, src);
369}
370
371SkMatrix44& SkMatrix44::operator=(const SkMatrix& src) {
372 initFromMatrix(fMat, src);
373 return *this;
374}
375
376SkMatrix44::operator SkMatrix() const {
377 SkMatrix dst;
378 dst.reset(); // setup our perspective correctly for identity
379
bsalomon@google.com72e49b82011-10-27 21:47:03 +0000380 dst[SkMatrix::kMScaleX] = SkMScalarToScalar(fMat[0][0]);
381 dst[SkMatrix::kMSkewX] = SkMScalarToScalar(fMat[1][0]);
382 dst[SkMatrix::kMTransX] = SkMScalarToScalar(fMat[3][0]);
reed@google.com8260a892011-06-13 14:02:52 +0000383
bsalomon@google.com72e49b82011-10-27 21:47:03 +0000384 dst[SkMatrix::kMSkewY] = SkMScalarToScalar(fMat[0][1]);
385 dst[SkMatrix::kMScaleY] = SkMScalarToScalar(fMat[1][1]);
386 dst[SkMatrix::kMTransY] = SkMScalarToScalar(fMat[3][1]);
reed@google.com8260a892011-06-13 14:02:52 +0000387
388 return dst;
389}