blob: 7dd174ad9346bb561d7d047734bc823430a91a54 [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
reed@google.com631940c2012-11-27 13:13:22 +000025bool SkMatrix44::operator==(const SkMatrix44& other) const {
26 const SkMScalar* a = &fMat[0][0];
27 const SkMScalar* b = &other.fMat[0][0];
28 for (int i = 0; i < 16; ++i) {
29 if (a[i] != b[i]) {
30 return false;
31 }
32 }
33 return true;
reed@google.com8260a892011-06-13 14:02:52 +000034}
35
36///////////////////////////////////////////////////////////////////////////////
37
reed@google.comda9fac02011-06-13 14:46:52 +000038void SkMatrix44::asColMajorf(float dst[]) const {
39 const SkMScalar* src = &fMat[0][0];
40#ifdef SK_MSCALAR_IS_DOUBLE
41 for (int i = 0; i < 16; ++i) {
42 dst[i] = SkMScalarToFloat(src[i]);
43 }
vollick@chromium.org5596a692012-11-13 20:12:00 +000044#elif defined SK_MSCALAR_IS_FLOAT
reed@google.comda9fac02011-06-13 14:46:52 +000045 memcpy(dst, src, 16 * sizeof(float));
46#endif
47}
48
49void SkMatrix44::asColMajord(double dst[]) const {
50 const SkMScalar* src = &fMat[0][0];
51#ifdef SK_MSCALAR_IS_DOUBLE
52 memcpy(dst, src, 16 * sizeof(double));
vollick@chromium.org5596a692012-11-13 20:12:00 +000053#elif defined SK_MSCALAR_IS_FLOAT
reed@google.comda9fac02011-06-13 14:46:52 +000054 for (int i = 0; i < 16; ++i) {
55 dst[i] = SkMScalarToDouble(src[i]);
56 }
57#endif
58}
59
60void SkMatrix44::asRowMajorf(float dst[]) const {
61 const SkMScalar* src = &fMat[0][0];
62 for (int i = 0; i < 4; ++i) {
63 dst[0] = SkMScalarToFloat(src[0]);
64 dst[4] = SkMScalarToFloat(src[1]);
65 dst[8] = SkMScalarToFloat(src[2]);
66 dst[12] = SkMScalarToFloat(src[3]);
67 src += 4;
68 dst += 1;
69 }
70}
71
72void SkMatrix44::asRowMajord(double dst[]) const {
73 const SkMScalar* src = &fMat[0][0];
74 for (int i = 0; i < 4; ++i) {
75 dst[0] = SkMScalarToDouble(src[0]);
76 dst[4] = SkMScalarToDouble(src[1]);
77 dst[8] = SkMScalarToDouble(src[2]);
78 dst[12] = SkMScalarToDouble(src[3]);
79 src += 4;
80 dst += 1;
81 }
82}
83
vollick@chromium.orgf11cf9f2012-11-19 21:02:06 +000084void SkMatrix44::setColMajorf(const float src[]) {
85 SkMScalar* dst = &fMat[0][0];
86#ifdef SK_MSCALAR_IS_DOUBLE
87 for (int i = 0; i < 16; ++i) {
88 dst[i] = SkMScalarToFloat(src[i]);
89 }
90#elif defined SK_MSCALAR_IS_FLOAT
91 memcpy(dst, src, 16 * sizeof(float));
92#endif
93}
94
95void SkMatrix44::setColMajord(const double src[]) {
96 SkMScalar* dst = &fMat[0][0];
97#ifdef SK_MSCALAR_IS_DOUBLE
98 memcpy(dst, src, 16 * sizeof(double));
99#elif defined SK_MSCALAR_IS_FLOAT
100 for (int i = 0; i < 16; ++i) {
101 dst[i] = SkMScalarToDouble(src[i]);
102 }
103#endif
104}
105
106void SkMatrix44::setRowMajorf(const float src[]) {
107 SkMScalar* dst = &fMat[0][0];
108 for (int i = 0; i < 4; ++i) {
109 dst[0] = SkMScalarToFloat(src[0]);
110 dst[4] = SkMScalarToFloat(src[1]);
111 dst[8] = SkMScalarToFloat(src[2]);
112 dst[12] = SkMScalarToFloat(src[3]);
113 src += 4;
114 dst += 1;
115 }
116}
117
118void SkMatrix44::setRowMajord(const double src[]) {
119 SkMScalar* dst = &fMat[0][0];
120 for (int i = 0; i < 4; ++i) {
121 dst[0] = SkMScalarToDouble(src[0]);
122 dst[4] = SkMScalarToDouble(src[1]);
123 dst[8] = SkMScalarToDouble(src[2]);
124 dst[12] = SkMScalarToDouble(src[3]);
125 src += 4;
126 dst += 1;
127 }
128}
129
reed@google.comda9fac02011-06-13 14:46:52 +0000130///////////////////////////////////////////////////////////////////////////////
131
reed@google.com8260a892011-06-13 14:02:52 +0000132bool SkMatrix44::isIdentity() const {
digit@google.com3e05f292012-01-10 10:00:59 +0000133 static const SkMScalar sIdentityMat[4][4] = {
134 { 1, 0, 0, 0 },
135 { 0, 1, 0, 0 },
136 { 0, 0, 1, 0 },
137 { 0, 0, 0, 1 },
138 };
139 return !memcmp(fMat, sIdentityMat, sizeof(fMat));
reed@google.com8260a892011-06-13 14:02:52 +0000140}
141
142///////////////////////////////////////////////////////////////////////////////
143
144void SkMatrix44::setIdentity() {
145 sk_bzero(fMat, sizeof(fMat));
146 fMat[0][0] = fMat[1][1] = fMat[2][2] = fMat[3][3] = 1;
147}
148
149void SkMatrix44::set3x3(SkMScalar m00, SkMScalar m01, SkMScalar m02,
150 SkMScalar m10, SkMScalar m11, SkMScalar m12,
151 SkMScalar m20, SkMScalar m21, SkMScalar m22) {
152 sk_bzero(fMat, sizeof(fMat));
153 fMat[0][0] = m00; fMat[0][1] = m01; fMat[0][2] = m02; fMat[0][3] = 0;
154 fMat[1][0] = m10; fMat[1][1] = m11; fMat[1][2] = m12; fMat[1][3] = 0;
155 fMat[2][0] = m20; fMat[2][1] = m21; fMat[2][2] = m22; fMat[2][3] = 0;
156 fMat[3][0] = 0; fMat[3][1] = 0; fMat[3][2] = 0; fMat[3][3] = 1;
157}
158
159///////////////////////////////////////////////////////////////////////////////
160
161void SkMatrix44::setTranslate(SkMScalar tx, SkMScalar ty, SkMScalar tz) {
162 this->setIdentity();
163 fMat[3][0] = tx;
164 fMat[3][1] = ty;
165 fMat[3][2] = tz;
166 fMat[3][3] = 1;
167}
168
169void SkMatrix44::preTranslate(SkMScalar dx, SkMScalar dy, SkMScalar dz) {
170 SkMatrix44 mat;
171 mat.setTranslate(dx, dy, dz);
172 this->preConcat(mat);
173}
174
175void SkMatrix44::postTranslate(SkMScalar dx, SkMScalar dy, SkMScalar dz) {
176 fMat[3][0] += dx;
177 fMat[3][1] += dy;
178 fMat[3][2] += dz;
179}
180
181///////////////////////////////////////////////////////////////////////////////
182
183void SkMatrix44::setScale(SkMScalar sx, SkMScalar sy, SkMScalar sz) {
184 sk_bzero(fMat, sizeof(fMat));
185 fMat[0][0] = sx;
186 fMat[1][1] = sy;
187 fMat[2][2] = sz;
188 fMat[3][3] = 1;
189}
190
191void SkMatrix44::preScale(SkMScalar sx, SkMScalar sy, SkMScalar sz) {
192 SkMatrix44 tmp;
193 tmp.setScale(sx, sy, sz);
194 this->preConcat(tmp);
195}
196
197void SkMatrix44::postScale(SkMScalar sx, SkMScalar sy, SkMScalar sz) {
198 for (int i = 0; i < 4; i++) {
199 fMat[i][0] *= sx;
200 fMat[i][1] *= sy;
201 fMat[i][2] *= sz;
202 }
203}
204
205///////////////////////////////////////////////////////////////////////////////
206
207void SkMatrix44::setRotateAbout(SkMScalar x, SkMScalar y, SkMScalar z,
208 SkMScalar radians) {
209 double len2 = x * x + y * y + z * z;
210 if (len2 != 1) {
211 if (len2 == 0) {
212 this->setIdentity();
213 return;
214 }
215 double scale = 1 / sqrt(len2);
bsalomon@google.com9d12f5c2011-09-29 18:08:18 +0000216 x = SkDoubleToMScalar(x * scale);
217 y = SkDoubleToMScalar(y * scale);
218 z = SkDoubleToMScalar(z * scale);
reed@google.com8260a892011-06-13 14:02:52 +0000219 }
220 this->setRotateAboutUnit(x, y, z, radians);
221}
222
223void SkMatrix44::setRotateAboutUnit(SkMScalar x, SkMScalar y, SkMScalar z,
224 SkMScalar radians) {
225 double c = cos(radians);
226 double s = sin(radians);
227 double C = 1 - c;
228 double xs = x * s;
229 double ys = y * s;
230 double zs = z * s;
231 double xC = x * C;
232 double yC = y * C;
233 double zC = z * C;
234 double xyC = x * yC;
235 double yzC = y * zC;
236 double zxC = z * xC;
237
238 // if you're looking at wikipedia, remember that we're column major.
bsalomon@google.com9d12f5c2011-09-29 18:08:18 +0000239 this->set3x3(SkDoubleToMScalar(x * xC + c), // scale x
240 SkDoubleToMScalar(xyC + zs), // skew x
241 SkDoubleToMScalar(zxC - ys), // trans x
242
243 SkDoubleToMScalar(xyC - zs), // skew y
244 SkDoubleToMScalar(y * yC + c), // scale y
245 SkDoubleToMScalar(yzC + xs), // trans y
246
247 SkDoubleToMScalar(zxC + ys), // persp x
248 SkDoubleToMScalar(yzC - xs), // persp y
249 SkDoubleToMScalar(z * zC + c)); // persp 2
reed@google.com8260a892011-06-13 14:02:52 +0000250}
251
252///////////////////////////////////////////////////////////////////////////////
253
254void SkMatrix44::setConcat(const SkMatrix44& a, const SkMatrix44& b) {
255 SkMScalar result[4][4];
256 for (int i = 0; i < 4; i++) {
257 for (int j = 0; j < 4; j++) {
258 double value = 0;
259 for (int k = 0; k < 4; k++) {
260 value += SkMScalarToDouble(a.fMat[k][i]) * b.fMat[j][k];
261 }
262 result[j][i] = SkDoubleToMScalar(value);
263 }
264 }
265 memcpy(fMat, result, sizeof(result));
266}
267
268///////////////////////////////////////////////////////////////////////////////
269
270static inline SkMScalar det2x2(double m00, double m01, double m10, double m11) {
bsalomon@google.com9d12f5c2011-09-29 18:08:18 +0000271 return SkDoubleToMScalar(m00 * m11 - m10 * m01);
reed@google.com8260a892011-06-13 14:02:52 +0000272}
273
274static inline double det3x3(double m00, double m01, double m02,
275 double m10, double m11, double m12,
276 double m20, double m21, double m22) {
277 return m00 * det2x2(m11, m12, m21, m22) -
278 m10 * det2x2(m01, m02, m21, m22) +
279 m20 * det2x2(m01, m02, m11, m12);
280}
281
282/** We always perform the calculation in doubles, to avoid prematurely losing
283 precision along the way. This relies on the compiler automatically
284 promoting our SkMScalar values to double (if needed).
285 */
286double SkMatrix44::determinant() const {
287 return fMat[0][0] * det3x3(fMat[1][1], fMat[1][2], fMat[1][3],
288 fMat[2][1], fMat[2][2], fMat[2][3],
289 fMat[3][1], fMat[3][2], fMat[3][3]) -
290 fMat[1][0] * det3x3(fMat[0][1], fMat[0][2], fMat[0][3],
291 fMat[2][1], fMat[2][2], fMat[2][3],
292 fMat[3][1], fMat[3][2], fMat[3][3]) +
293 fMat[2][0] * det3x3(fMat[0][1], fMat[0][2], fMat[0][3],
294 fMat[1][1], fMat[1][2], fMat[1][3],
295 fMat[3][1], fMat[3][2], fMat[3][3]) -
296 fMat[3][0] * det3x3(fMat[0][1], fMat[0][2], fMat[0][3],
297 fMat[1][1], fMat[1][2], fMat[1][3],
298 fMat[2][1], fMat[2][2], fMat[2][3]);
299}
300
301///////////////////////////////////////////////////////////////////////////////
302
303// just picked a small value. not sure how to pick the "right" one
304#define TOO_SMALL_FOR_DETERMINANT (1.e-8)
305
306static inline double dabs(double x) {
307 if (x < 0) {
308 x = -x;
309 }
310 return x;
311}
312
313bool SkMatrix44::invert(SkMatrix44* inverse) const {
314 double det = this->determinant();
315 if (dabs(det) < TOO_SMALL_FOR_DETERMINANT) {
316 return false;
317 }
318 if (NULL == inverse) {
319 return true;
320 }
321
322 // we explicitly promote to doubles to keep the intermediate values in
323 // higher precision (assuming SkMScalar isn't already a double)
324 double m00 = fMat[0][0];
325 double m01 = fMat[0][1];
326 double m02 = fMat[0][2];
327 double m03 = fMat[0][3];
328 double m10 = fMat[1][0];
329 double m11 = fMat[1][1];
330 double m12 = fMat[1][2];
331 double m13 = fMat[1][3];
332 double m20 = fMat[2][0];
333 double m21 = fMat[2][1];
334 double m22 = fMat[2][2];
335 double m23 = fMat[2][3];
336 double m30 = fMat[3][0];
337 double m31 = fMat[3][1];
338 double m32 = fMat[3][2];
339 double m33 = fMat[3][3];
340
341 double tmp[4][4];
342
343 tmp[0][0] = m12*m23*m31 - m13*m22*m31 + m13*m21*m32 - m11*m23*m32 - m12*m21*m33 + m11*m22*m33;
344 tmp[0][1] = m03*m22*m31 - m02*m23*m31 - m03*m21*m32 + m01*m23*m32 + m02*m21*m33 - m01*m22*m33;
345 tmp[0][2] = m02*m13*m31 - m03*m12*m31 + m03*m11*m32 - m01*m13*m32 - m02*m11*m33 + m01*m12*m33;
346 tmp[0][3] = m03*m12*m21 - m02*m13*m21 - m03*m11*m22 + m01*m13*m22 + m02*m11*m23 - m01*m12*m23;
347 tmp[1][0] = m13*m22*m30 - m12*m23*m30 - m13*m20*m32 + m10*m23*m32 + m12*m20*m33 - m10*m22*m33;
348 tmp[1][1] = m02*m23*m30 - m03*m22*m30 + m03*m20*m32 - m00*m23*m32 - m02*m20*m33 + m00*m22*m33;
349 tmp[1][2] = m03*m12*m30 - m02*m13*m30 - m03*m10*m32 + m00*m13*m32 + m02*m10*m33 - m00*m12*m33;
350 tmp[1][3] = m02*m13*m20 - m03*m12*m20 + m03*m10*m22 - m00*m13*m22 - m02*m10*m23 + m00*m12*m23;
351 tmp[2][0] = m11*m23*m30 - m13*m21*m30 + m13*m20*m31 - m10*m23*m31 - m11*m20*m33 + m10*m21*m33;
352 tmp[2][1] = m03*m21*m30 - m01*m23*m30 - m03*m20*m31 + m00*m23*m31 + m01*m20*m33 - m00*m21*m33;
353 tmp[2][2] = m01*m13*m30 - m03*m11*m30 + m03*m10*m31 - m00*m13*m31 - m01*m10*m33 + m00*m11*m33;
354 tmp[2][3] = m03*m11*m20 - m01*m13*m20 - m03*m10*m21 + m00*m13*m21 + m01*m10*m23 - m00*m11*m23;
355 tmp[3][0] = m12*m21*m30 - m11*m22*m30 - m12*m20*m31 + m10*m22*m31 + m11*m20*m32 - m10*m21*m32;
356 tmp[3][1] = m01*m22*m30 - m02*m21*m30 + m02*m20*m31 - m00*m22*m31 - m01*m20*m32 + m00*m21*m32;
357 tmp[3][2] = m02*m11*m30 - m01*m12*m30 - m02*m10*m31 + m00*m12*m31 + m01*m10*m32 - m00*m11*m32;
358 tmp[3][3] = m01*m12*m20 - m02*m11*m20 + m02*m10*m21 - m00*m12*m21 - m01*m10*m22 + m00*m11*m22;
359
360 double invDet = 1.0 / det;
361 for (int i = 0; i < 4; i++) {
362 for (int j = 0; j < 4; j++) {
363 inverse->fMat[i][j] = SkDoubleToMScalar(tmp[i][j] * invDet);
364 }
365 }
366 return true;
367}
368
369///////////////////////////////////////////////////////////////////////////////
370
vollick@chromium.org9b21c252012-11-14 21:33:55 +0000371void SkMatrix44::transpose() {
372 SkTSwap(fMat[0][1], fMat[1][0]);
373 SkTSwap(fMat[0][2], fMat[2][0]);
374 SkTSwap(fMat[0][3], fMat[3][0]);
375 SkTSwap(fMat[1][2], fMat[2][1]);
376 SkTSwap(fMat[1][3], fMat[3][1]);
377 SkTSwap(fMat[2][3], fMat[3][2]);
378}
379
380///////////////////////////////////////////////////////////////////////////////
381
reed@google.com1ea95be2012-11-09 21:39:48 +0000382void SkMatrix44::mapScalars(const SkScalar src[4], SkScalar dst[4]) const {
reed@google.com8260a892011-06-13 14:02:52 +0000383 SkScalar result[4];
384 for (int i = 0; i < 4; i++) {
385 SkMScalar value = 0;
386 for (int j = 0; j < 4; j++) {
387 value += fMat[j][i] * src[j];
388 }
bsalomon@google.com72e49b82011-10-27 21:47:03 +0000389 result[i] = SkMScalarToScalar(value);
reed@google.com8260a892011-06-13 14:02:52 +0000390 }
391 memcpy(dst, result, sizeof(result));
392}
393
reed@google.com1ea95be2012-11-09 21:39:48 +0000394#ifdef SK_MSCALAR_IS_DOUBLE
395void SkMatrix44::mapMScalars(const SkMScalar src[4], SkMScalar dst[4]) const {
396 SkMScalar result[4];
397 for (int i = 0; i < 4; i++) {
398 SkMScalar value = 0;
399 for (int j = 0; j < 4; j++) {
400 value += fMat[j][i] * src[j];
401 }
402 result[i] = SkMScalarToScalar(value);
403 }
404 memcpy(dst, result, sizeof(result));
405}
406#endif
407
reed@google.com8260a892011-06-13 14:02:52 +0000408///////////////////////////////////////////////////////////////////////////////
409
410void SkMatrix44::dump() const {
tomhudson@google.com9ac4a892011-06-28 13:53:13 +0000411 static const char* format =
412 "[%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 +0000413#if 0
tomhudson@google.com9ac4a892011-06-28 13:53:13 +0000414 SkDebugf(format,
reed@google.com8260a892011-06-13 14:02:52 +0000415 fMat[0][0], fMat[1][0], fMat[2][0], fMat[3][0],
416 fMat[0][1], fMat[1][1], fMat[2][1], fMat[3][1],
417 fMat[0][2], fMat[1][2], fMat[2][2], fMat[3][2],
418 fMat[0][3], fMat[1][3], fMat[2][3], fMat[3][3]);
tomhudson@google.com9ac4a892011-06-28 13:53:13 +0000419#else
420 SkDebugf(format,
421 fMat[0][0], fMat[0][1], fMat[0][2], fMat[0][3],
422 fMat[1][0], fMat[1][1], fMat[1][2], fMat[1][3],
423 fMat[2][0], fMat[2][1], fMat[2][2], fMat[2][3],
424 fMat[3][0], fMat[3][1], fMat[3][2], fMat[3][3]);
reed@google.com8260a892011-06-13 14:02:52 +0000425#endif
426}
427
428///////////////////////////////////////////////////////////////////////////////
429
430static void initFromMatrix(SkMScalar dst[4][4], const SkMatrix& src) {
431 sk_bzero(dst, 16 * sizeof(SkMScalar));
bsalomon@google.com72e49b82011-10-27 21:47:03 +0000432 dst[0][0] = SkScalarToMScalar(src[SkMatrix::kMScaleX]);
433 dst[1][0] = SkScalarToMScalar(src[SkMatrix::kMSkewX]);
434 dst[3][0] = SkScalarToMScalar(src[SkMatrix::kMTransX]);
435 dst[0][1] = SkScalarToMScalar(src[SkMatrix::kMSkewY]);
436 dst[1][1] = SkScalarToMScalar(src[SkMatrix::kMScaleY]);
437 dst[3][1] = SkScalarToMScalar(src[SkMatrix::kMTransY]);
reed@google.com8260a892011-06-13 14:02:52 +0000438 dst[2][2] = dst[3][3] = 1;
439}
440
441SkMatrix44::SkMatrix44(const SkMatrix& src) {
442 initFromMatrix(fMat, src);
443}
444
445SkMatrix44& SkMatrix44::operator=(const SkMatrix& src) {
446 initFromMatrix(fMat, src);
447 return *this;
448}
449
450SkMatrix44::operator SkMatrix() const {
451 SkMatrix dst;
452 dst.reset(); // setup our perspective correctly for identity
453
bsalomon@google.com72e49b82011-10-27 21:47:03 +0000454 dst[SkMatrix::kMScaleX] = SkMScalarToScalar(fMat[0][0]);
455 dst[SkMatrix::kMSkewX] = SkMScalarToScalar(fMat[1][0]);
456 dst[SkMatrix::kMTransX] = SkMScalarToScalar(fMat[3][0]);
reed@google.com8260a892011-06-13 14:02:52 +0000457
bsalomon@google.com72e49b82011-10-27 21:47:03 +0000458 dst[SkMatrix::kMSkewY] = SkMScalarToScalar(fMat[0][1]);
459 dst[SkMatrix::kMScaleY] = SkMScalarToScalar(fMat[1][1]);
460 dst[SkMatrix::kMTransY] = SkMScalarToScalar(fMat[3][1]);
reed@google.com8260a892011-06-13 14:02:52 +0000461
462 return dst;
463}