blob: 4fe82deaf661ea114e2937d2f0e701c4886123cb [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 +000087bool SkMatrix44::isIdentity() const {
digit@google.com3e05f292012-01-10 10:00:59 +000088 static const SkMScalar sIdentityMat[4][4] = {
89 { 1, 0, 0, 0 },
90 { 0, 1, 0, 0 },
91 { 0, 0, 1, 0 },
92 { 0, 0, 0, 1 },
93 };
94 return !memcmp(fMat, sIdentityMat, sizeof(fMat));
reed@google.com8260a892011-06-13 14:02:52 +000095}
96
97///////////////////////////////////////////////////////////////////////////////
98
99void SkMatrix44::setIdentity() {
100 sk_bzero(fMat, sizeof(fMat));
101 fMat[0][0] = fMat[1][1] = fMat[2][2] = fMat[3][3] = 1;
102}
103
104void SkMatrix44::set3x3(SkMScalar m00, SkMScalar m01, SkMScalar m02,
105 SkMScalar m10, SkMScalar m11, SkMScalar m12,
106 SkMScalar m20, SkMScalar m21, SkMScalar m22) {
107 sk_bzero(fMat, sizeof(fMat));
108 fMat[0][0] = m00; fMat[0][1] = m01; fMat[0][2] = m02; fMat[0][3] = 0;
109 fMat[1][0] = m10; fMat[1][1] = m11; fMat[1][2] = m12; fMat[1][3] = 0;
110 fMat[2][0] = m20; fMat[2][1] = m21; fMat[2][2] = m22; fMat[2][3] = 0;
111 fMat[3][0] = 0; fMat[3][1] = 0; fMat[3][2] = 0; fMat[3][3] = 1;
112}
113
114///////////////////////////////////////////////////////////////////////////////
115
116void SkMatrix44::setTranslate(SkMScalar tx, SkMScalar ty, SkMScalar tz) {
117 this->setIdentity();
118 fMat[3][0] = tx;
119 fMat[3][1] = ty;
120 fMat[3][2] = tz;
121 fMat[3][3] = 1;
122}
123
124void SkMatrix44::preTranslate(SkMScalar dx, SkMScalar dy, SkMScalar dz) {
125 SkMatrix44 mat;
126 mat.setTranslate(dx, dy, dz);
127 this->preConcat(mat);
128}
129
130void SkMatrix44::postTranslate(SkMScalar dx, SkMScalar dy, SkMScalar dz) {
131 fMat[3][0] += dx;
132 fMat[3][1] += dy;
133 fMat[3][2] += dz;
134}
135
136///////////////////////////////////////////////////////////////////////////////
137
138void SkMatrix44::setScale(SkMScalar sx, SkMScalar sy, SkMScalar sz) {
139 sk_bzero(fMat, sizeof(fMat));
140 fMat[0][0] = sx;
141 fMat[1][1] = sy;
142 fMat[2][2] = sz;
143 fMat[3][3] = 1;
144}
145
146void SkMatrix44::preScale(SkMScalar sx, SkMScalar sy, SkMScalar sz) {
147 SkMatrix44 tmp;
148 tmp.setScale(sx, sy, sz);
149 this->preConcat(tmp);
150}
151
152void SkMatrix44::postScale(SkMScalar sx, SkMScalar sy, SkMScalar sz) {
153 for (int i = 0; i < 4; i++) {
154 fMat[i][0] *= sx;
155 fMat[i][1] *= sy;
156 fMat[i][2] *= sz;
157 }
158}
159
160///////////////////////////////////////////////////////////////////////////////
161
162void SkMatrix44::setRotateAbout(SkMScalar x, SkMScalar y, SkMScalar z,
163 SkMScalar radians) {
164 double len2 = x * x + y * y + z * z;
165 if (len2 != 1) {
166 if (len2 == 0) {
167 this->setIdentity();
168 return;
169 }
170 double scale = 1 / sqrt(len2);
bsalomon@google.com9d12f5c2011-09-29 18:08:18 +0000171 x = SkDoubleToMScalar(x * scale);
172 y = SkDoubleToMScalar(y * scale);
173 z = SkDoubleToMScalar(z * scale);
reed@google.com8260a892011-06-13 14:02:52 +0000174 }
175 this->setRotateAboutUnit(x, y, z, radians);
176}
177
178void SkMatrix44::setRotateAboutUnit(SkMScalar x, SkMScalar y, SkMScalar z,
179 SkMScalar radians) {
180 double c = cos(radians);
181 double s = sin(radians);
182 double C = 1 - c;
183 double xs = x * s;
184 double ys = y * s;
185 double zs = z * s;
186 double xC = x * C;
187 double yC = y * C;
188 double zC = z * C;
189 double xyC = x * yC;
190 double yzC = y * zC;
191 double zxC = z * xC;
192
193 // if you're looking at wikipedia, remember that we're column major.
bsalomon@google.com9d12f5c2011-09-29 18:08:18 +0000194 this->set3x3(SkDoubleToMScalar(x * xC + c), // scale x
195 SkDoubleToMScalar(xyC + zs), // skew x
196 SkDoubleToMScalar(zxC - ys), // trans x
197
198 SkDoubleToMScalar(xyC - zs), // skew y
199 SkDoubleToMScalar(y * yC + c), // scale y
200 SkDoubleToMScalar(yzC + xs), // trans y
201
202 SkDoubleToMScalar(zxC + ys), // persp x
203 SkDoubleToMScalar(yzC - xs), // persp y
204 SkDoubleToMScalar(z * zC + c)); // persp 2
reed@google.com8260a892011-06-13 14:02:52 +0000205}
206
207///////////////////////////////////////////////////////////////////////////////
208
209void SkMatrix44::setConcat(const SkMatrix44& a, const SkMatrix44& b) {
210 SkMScalar result[4][4];
211 for (int i = 0; i < 4; i++) {
212 for (int j = 0; j < 4; j++) {
213 double value = 0;
214 for (int k = 0; k < 4; k++) {
215 value += SkMScalarToDouble(a.fMat[k][i]) * b.fMat[j][k];
216 }
217 result[j][i] = SkDoubleToMScalar(value);
218 }
219 }
220 memcpy(fMat, result, sizeof(result));
221}
222
223///////////////////////////////////////////////////////////////////////////////
224
225static inline SkMScalar det2x2(double m00, double m01, double m10, double m11) {
bsalomon@google.com9d12f5c2011-09-29 18:08:18 +0000226 return SkDoubleToMScalar(m00 * m11 - m10 * m01);
reed@google.com8260a892011-06-13 14:02:52 +0000227}
228
229static inline double det3x3(double m00, double m01, double m02,
230 double m10, double m11, double m12,
231 double m20, double m21, double m22) {
232 return m00 * det2x2(m11, m12, m21, m22) -
233 m10 * det2x2(m01, m02, m21, m22) +
234 m20 * det2x2(m01, m02, m11, m12);
235}
236
237/** We always perform the calculation in doubles, to avoid prematurely losing
238 precision along the way. This relies on the compiler automatically
239 promoting our SkMScalar values to double (if needed).
240 */
241double SkMatrix44::determinant() const {
242 return fMat[0][0] * det3x3(fMat[1][1], fMat[1][2], fMat[1][3],
243 fMat[2][1], fMat[2][2], fMat[2][3],
244 fMat[3][1], fMat[3][2], fMat[3][3]) -
245 fMat[1][0] * det3x3(fMat[0][1], fMat[0][2], fMat[0][3],
246 fMat[2][1], fMat[2][2], fMat[2][3],
247 fMat[3][1], fMat[3][2], fMat[3][3]) +
248 fMat[2][0] * det3x3(fMat[0][1], fMat[0][2], fMat[0][3],
249 fMat[1][1], fMat[1][2], fMat[1][3],
250 fMat[3][1], fMat[3][2], fMat[3][3]) -
251 fMat[3][0] * det3x3(fMat[0][1], fMat[0][2], fMat[0][3],
252 fMat[1][1], fMat[1][2], fMat[1][3],
253 fMat[2][1], fMat[2][2], fMat[2][3]);
254}
255
256///////////////////////////////////////////////////////////////////////////////
257
258// just picked a small value. not sure how to pick the "right" one
259#define TOO_SMALL_FOR_DETERMINANT (1.e-8)
260
261static inline double dabs(double x) {
262 if (x < 0) {
263 x = -x;
264 }
265 return x;
266}
267
268bool SkMatrix44::invert(SkMatrix44* inverse) const {
269 double det = this->determinant();
270 if (dabs(det) < TOO_SMALL_FOR_DETERMINANT) {
271 return false;
272 }
273 if (NULL == inverse) {
274 return true;
275 }
276
277 // we explicitly promote to doubles to keep the intermediate values in
278 // higher precision (assuming SkMScalar isn't already a double)
279 double m00 = fMat[0][0];
280 double m01 = fMat[0][1];
281 double m02 = fMat[0][2];
282 double m03 = fMat[0][3];
283 double m10 = fMat[1][0];
284 double m11 = fMat[1][1];
285 double m12 = fMat[1][2];
286 double m13 = fMat[1][3];
287 double m20 = fMat[2][0];
288 double m21 = fMat[2][1];
289 double m22 = fMat[2][2];
290 double m23 = fMat[2][3];
291 double m30 = fMat[3][0];
292 double m31 = fMat[3][1];
293 double m32 = fMat[3][2];
294 double m33 = fMat[3][3];
295
296 double tmp[4][4];
297
298 tmp[0][0] = m12*m23*m31 - m13*m22*m31 + m13*m21*m32 - m11*m23*m32 - m12*m21*m33 + m11*m22*m33;
299 tmp[0][1] = m03*m22*m31 - m02*m23*m31 - m03*m21*m32 + m01*m23*m32 + m02*m21*m33 - m01*m22*m33;
300 tmp[0][2] = m02*m13*m31 - m03*m12*m31 + m03*m11*m32 - m01*m13*m32 - m02*m11*m33 + m01*m12*m33;
301 tmp[0][3] = m03*m12*m21 - m02*m13*m21 - m03*m11*m22 + m01*m13*m22 + m02*m11*m23 - m01*m12*m23;
302 tmp[1][0] = m13*m22*m30 - m12*m23*m30 - m13*m20*m32 + m10*m23*m32 + m12*m20*m33 - m10*m22*m33;
303 tmp[1][1] = m02*m23*m30 - m03*m22*m30 + m03*m20*m32 - m00*m23*m32 - m02*m20*m33 + m00*m22*m33;
304 tmp[1][2] = m03*m12*m30 - m02*m13*m30 - m03*m10*m32 + m00*m13*m32 + m02*m10*m33 - m00*m12*m33;
305 tmp[1][3] = m02*m13*m20 - m03*m12*m20 + m03*m10*m22 - m00*m13*m22 - m02*m10*m23 + m00*m12*m23;
306 tmp[2][0] = m11*m23*m30 - m13*m21*m30 + m13*m20*m31 - m10*m23*m31 - m11*m20*m33 + m10*m21*m33;
307 tmp[2][1] = m03*m21*m30 - m01*m23*m30 - m03*m20*m31 + m00*m23*m31 + m01*m20*m33 - m00*m21*m33;
308 tmp[2][2] = m01*m13*m30 - m03*m11*m30 + m03*m10*m31 - m00*m13*m31 - m01*m10*m33 + m00*m11*m33;
309 tmp[2][3] = m03*m11*m20 - m01*m13*m20 - m03*m10*m21 + m00*m13*m21 + m01*m10*m23 - m00*m11*m23;
310 tmp[3][0] = m12*m21*m30 - m11*m22*m30 - m12*m20*m31 + m10*m22*m31 + m11*m20*m32 - m10*m21*m32;
311 tmp[3][1] = m01*m22*m30 - m02*m21*m30 + m02*m20*m31 - m00*m22*m31 - m01*m20*m32 + m00*m21*m32;
312 tmp[3][2] = m02*m11*m30 - m01*m12*m30 - m02*m10*m31 + m00*m12*m31 + m01*m10*m32 - m00*m11*m32;
313 tmp[3][3] = m01*m12*m20 - m02*m11*m20 + m02*m10*m21 - m00*m12*m21 - m01*m10*m22 + m00*m11*m22;
314
315 double invDet = 1.0 / det;
316 for (int i = 0; i < 4; i++) {
317 for (int j = 0; j < 4; j++) {
318 inverse->fMat[i][j] = SkDoubleToMScalar(tmp[i][j] * invDet);
319 }
320 }
321 return true;
322}
323
324///////////////////////////////////////////////////////////////////////////////
325
reed@google.com1ea95be2012-11-09 21:39:48 +0000326void SkMatrix44::mapScalars(const SkScalar src[4], SkScalar dst[4]) const {
reed@google.com8260a892011-06-13 14:02:52 +0000327 SkScalar result[4];
328 for (int i = 0; i < 4; i++) {
329 SkMScalar value = 0;
330 for (int j = 0; j < 4; j++) {
331 value += fMat[j][i] * src[j];
332 }
bsalomon@google.com72e49b82011-10-27 21:47:03 +0000333 result[i] = SkMScalarToScalar(value);
reed@google.com8260a892011-06-13 14:02:52 +0000334 }
335 memcpy(dst, result, sizeof(result));
336}
337
reed@google.com1ea95be2012-11-09 21:39:48 +0000338#ifdef SK_MSCALAR_IS_DOUBLE
339void SkMatrix44::mapMScalars(const SkMScalar src[4], SkMScalar dst[4]) const {
340 SkMScalar result[4];
341 for (int i = 0; i < 4; i++) {
342 SkMScalar value = 0;
343 for (int j = 0; j < 4; j++) {
344 value += fMat[j][i] * src[j];
345 }
346 result[i] = SkMScalarToScalar(value);
347 }
348 memcpy(dst, result, sizeof(result));
349}
350#endif
351
reed@google.com8260a892011-06-13 14:02:52 +0000352///////////////////////////////////////////////////////////////////////////////
353
354void SkMatrix44::dump() const {
tomhudson@google.com9ac4a892011-06-28 13:53:13 +0000355 static const char* format =
356 "[%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 +0000357#if 0
tomhudson@google.com9ac4a892011-06-28 13:53:13 +0000358 SkDebugf(format,
reed@google.com8260a892011-06-13 14:02:52 +0000359 fMat[0][0], fMat[1][0], fMat[2][0], fMat[3][0],
360 fMat[0][1], fMat[1][1], fMat[2][1], fMat[3][1],
361 fMat[0][2], fMat[1][2], fMat[2][2], fMat[3][2],
362 fMat[0][3], fMat[1][3], fMat[2][3], fMat[3][3]);
tomhudson@google.com9ac4a892011-06-28 13:53:13 +0000363#else
364 SkDebugf(format,
365 fMat[0][0], fMat[0][1], fMat[0][2], fMat[0][3],
366 fMat[1][0], fMat[1][1], fMat[1][2], fMat[1][3],
367 fMat[2][0], fMat[2][1], fMat[2][2], fMat[2][3],
368 fMat[3][0], fMat[3][1], fMat[3][2], fMat[3][3]);
reed@google.com8260a892011-06-13 14:02:52 +0000369#endif
370}
371
372///////////////////////////////////////////////////////////////////////////////
373
374static void initFromMatrix(SkMScalar dst[4][4], const SkMatrix& src) {
375 sk_bzero(dst, 16 * sizeof(SkMScalar));
bsalomon@google.com72e49b82011-10-27 21:47:03 +0000376 dst[0][0] = SkScalarToMScalar(src[SkMatrix::kMScaleX]);
377 dst[1][0] = SkScalarToMScalar(src[SkMatrix::kMSkewX]);
378 dst[3][0] = SkScalarToMScalar(src[SkMatrix::kMTransX]);
379 dst[0][1] = SkScalarToMScalar(src[SkMatrix::kMSkewY]);
380 dst[1][1] = SkScalarToMScalar(src[SkMatrix::kMScaleY]);
381 dst[3][1] = SkScalarToMScalar(src[SkMatrix::kMTransY]);
reed@google.com8260a892011-06-13 14:02:52 +0000382 dst[2][2] = dst[3][3] = 1;
383}
384
385SkMatrix44::SkMatrix44(const SkMatrix& src) {
386 initFromMatrix(fMat, src);
387}
388
389SkMatrix44& SkMatrix44::operator=(const SkMatrix& src) {
390 initFromMatrix(fMat, src);
391 return *this;
392}
393
394SkMatrix44::operator SkMatrix() const {
395 SkMatrix dst;
396 dst.reset(); // setup our perspective correctly for identity
397
bsalomon@google.com72e49b82011-10-27 21:47:03 +0000398 dst[SkMatrix::kMScaleX] = SkMScalarToScalar(fMat[0][0]);
399 dst[SkMatrix::kMSkewX] = SkMScalarToScalar(fMat[1][0]);
400 dst[SkMatrix::kMTransX] = SkMScalarToScalar(fMat[3][0]);
reed@google.com8260a892011-06-13 14:02:52 +0000401
bsalomon@google.com72e49b82011-10-27 21:47:03 +0000402 dst[SkMatrix::kMSkewY] = SkMScalarToScalar(fMat[0][1]);
403 dst[SkMatrix::kMScaleY] = SkMScalarToScalar(fMat[1][1]);
404 dst[SkMatrix::kMTransY] = SkMScalarToScalar(fMat[3][1]);
reed@google.com8260a892011-06-13 14:02:52 +0000405
406 return dst;
407}