blob: e899cf81e3410ff931cfa8b4d1c1aa1b0f31de93 [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
reed@google.com8260a892011-06-13 14:02:52 +000013SkMatrix44::SkMatrix44(const SkMatrix44& src) {
14 memcpy(this, &src, sizeof(src));
15}
16
17SkMatrix44::SkMatrix44(const SkMatrix44& a, const SkMatrix44& b) {
18 this->setConcat(a, b);
19}
20
reed@google.com7d683352012-12-03 21:19:52 +000021static inline bool eq4(const SkMScalar* SK_RESTRICT a,
22 const SkMScalar* SK_RESTRICT b) {
23 return (a[0] == b[0]) & (a[1] == b[1]) & (a[2] == b[2]) & (a[3] == b[3]);
24}
jamesr@chromium.orgdeb4c162012-11-29 21:17:16 +000025
reed@google.com7d683352012-12-03 21:19:52 +000026bool SkMatrix44::operator==(const SkMatrix44& other) const {
27 if (this == &other) {
28 return true;
29 }
30
31 if (this->isTriviallyIdentity() && other.isTriviallyIdentity()) {
32 return true;
33 }
34
35 const SkMScalar* SK_RESTRICT a = &fMat[0][0];
36 const SkMScalar* SK_RESTRICT b = &other.fMat[0][0];
37
38#if 0
reed@google.com631940c2012-11-27 13:13:22 +000039 for (int i = 0; i < 16; ++i) {
40 if (a[i] != b[i]) {
41 return false;
42 }
43 }
44 return true;
reed@google.com7d683352012-12-03 21:19:52 +000045#else
46 // to reduce branch instructions, we compare 4 at a time.
47 // see bench/Matrix44Bench.cpp for test.
48 if (!eq4(&a[0], &b[0])) {
49 return false;
50 }
51 if (!eq4(&a[4], &b[4])) {
52 return false;
53 }
54 if (!eq4(&a[8], &b[8])) {
55 return false;
56 }
57 return eq4(&a[12], &b[12]);
58#endif
59}
60
61///////////////////////////////////////////////////////////////////////////////
62
63int SkMatrix44::computeTypeMask() const {
64 unsigned mask = 0;
skia.committer@gmail.com0264fb42012-12-06 02:01:25 +000065
reed@google.com7d683352012-12-03 21:19:52 +000066 if (0 != perspX() || 0 != perspY() || 0 != perspZ() || 1 != fMat[3][3]) {
67 return kTranslate_Mask | kScale_Mask | kAffine_Mask | kPerspective_Mask;
68 }
69
70 if (0 != transX() || 0 != transY() || 0 != transZ()) {
71 mask |= kTranslate_Mask;
72 }
73
74 if (1 != scaleX() || 1 != scaleY() || 1 != scaleZ()) {
75 mask |= kScale_Mask;
76 }
77
78 if (0 != fMat[1][0] || 0 != fMat[0][1] || 0 != fMat[0][2] ||
79 0 != fMat[2][0] || 0 != fMat[1][2] || 0 != fMat[2][1]) {
80 mask |= kAffine_Mask;
81 }
82
83 return mask;
reed@google.com8260a892011-06-13 14:02:52 +000084}
85
86///////////////////////////////////////////////////////////////////////////////
87
reed@google.comda9fac02011-06-13 14:46:52 +000088void SkMatrix44::asColMajorf(float dst[]) const {
89 const SkMScalar* src = &fMat[0][0];
90#ifdef SK_MSCALAR_IS_DOUBLE
91 for (int i = 0; i < 16; ++i) {
92 dst[i] = SkMScalarToFloat(src[i]);
93 }
vollick@chromium.org5596a692012-11-13 20:12:00 +000094#elif defined SK_MSCALAR_IS_FLOAT
reed@google.comda9fac02011-06-13 14:46:52 +000095 memcpy(dst, src, 16 * sizeof(float));
96#endif
97}
98
99void SkMatrix44::asColMajord(double dst[]) const {
100 const SkMScalar* src = &fMat[0][0];
101#ifdef SK_MSCALAR_IS_DOUBLE
102 memcpy(dst, src, 16 * sizeof(double));
vollick@chromium.org5596a692012-11-13 20:12:00 +0000103#elif defined SK_MSCALAR_IS_FLOAT
reed@google.comda9fac02011-06-13 14:46:52 +0000104 for (int i = 0; i < 16; ++i) {
105 dst[i] = SkMScalarToDouble(src[i]);
106 }
107#endif
108}
109
110void SkMatrix44::asRowMajorf(float dst[]) const {
111 const SkMScalar* src = &fMat[0][0];
112 for (int i = 0; i < 4; ++i) {
113 dst[0] = SkMScalarToFloat(src[0]);
114 dst[4] = SkMScalarToFloat(src[1]);
115 dst[8] = SkMScalarToFloat(src[2]);
116 dst[12] = SkMScalarToFloat(src[3]);
117 src += 4;
118 dst += 1;
119 }
120}
121
122void SkMatrix44::asRowMajord(double dst[]) const {
123 const SkMScalar* src = &fMat[0][0];
124 for (int i = 0; i < 4; ++i) {
125 dst[0] = SkMScalarToDouble(src[0]);
126 dst[4] = SkMScalarToDouble(src[1]);
127 dst[8] = SkMScalarToDouble(src[2]);
128 dst[12] = SkMScalarToDouble(src[3]);
129 src += 4;
130 dst += 1;
131 }
132}
133
vollick@chromium.orgf11cf9f2012-11-19 21:02:06 +0000134void SkMatrix44::setColMajorf(const float src[]) {
135 SkMScalar* dst = &fMat[0][0];
136#ifdef SK_MSCALAR_IS_DOUBLE
137 for (int i = 0; i < 16; ++i) {
138 dst[i] = SkMScalarToFloat(src[i]);
139 }
140#elif defined SK_MSCALAR_IS_FLOAT
141 memcpy(dst, src, 16 * sizeof(float));
142#endif
reed@google.com7d683352012-12-03 21:19:52 +0000143
144 this->dirtyTypeMask();
vollick@chromium.orgf11cf9f2012-11-19 21:02:06 +0000145}
146
147void SkMatrix44::setColMajord(const double src[]) {
148 SkMScalar* dst = &fMat[0][0];
149#ifdef SK_MSCALAR_IS_DOUBLE
150 memcpy(dst, src, 16 * sizeof(double));
151#elif defined SK_MSCALAR_IS_FLOAT
152 for (int i = 0; i < 16; ++i) {
robertphillips@google.com93f03322012-12-03 17:35:19 +0000153 dst[i] = SkDoubleToMScalar(src[i]);
vollick@chromium.orgf11cf9f2012-11-19 21:02:06 +0000154 }
155#endif
reed@google.com7d683352012-12-03 21:19:52 +0000156
157 this->dirtyTypeMask();
vollick@chromium.orgf11cf9f2012-11-19 21:02:06 +0000158}
159
160void SkMatrix44::setRowMajorf(const float src[]) {
161 SkMScalar* dst = &fMat[0][0];
162 for (int i = 0; i < 4; ++i) {
163 dst[0] = SkMScalarToFloat(src[0]);
164 dst[4] = SkMScalarToFloat(src[1]);
165 dst[8] = SkMScalarToFloat(src[2]);
166 dst[12] = SkMScalarToFloat(src[3]);
167 src += 4;
168 dst += 1;
169 }
reed@google.com7d683352012-12-03 21:19:52 +0000170 this->dirtyTypeMask();
vollick@chromium.orgf11cf9f2012-11-19 21:02:06 +0000171}
172
173void SkMatrix44::setRowMajord(const double src[]) {
174 SkMScalar* dst = &fMat[0][0];
175 for (int i = 0; i < 4; ++i) {
robertphillips@google.com93f03322012-12-03 17:35:19 +0000176 dst[0] = SkDoubleToMScalar(src[0]);
177 dst[4] = SkDoubleToMScalar(src[1]);
178 dst[8] = SkDoubleToMScalar(src[2]);
179 dst[12] = SkDoubleToMScalar(src[3]);
vollick@chromium.orgf11cf9f2012-11-19 21:02:06 +0000180 src += 4;
181 dst += 1;
182 }
reed@google.com7d683352012-12-03 21:19:52 +0000183 this->dirtyTypeMask();
vollick@chromium.orgf11cf9f2012-11-19 21:02:06 +0000184}
185
reed@google.comda9fac02011-06-13 14:46:52 +0000186///////////////////////////////////////////////////////////////////////////////
187
reed@google.com7d683352012-12-03 21:19:52 +0000188const SkMatrix44& SkMatrix44::I() {
reed@google.com1adad342012-12-10 21:21:27 +0000189 static const SkMatrix44 gIdentity44(kIdentity_Constructor);
190 return gIdentity44;
reed@google.com8260a892011-06-13 14:02:52 +0000191}
192
reed@google.com8260a892011-06-13 14:02:52 +0000193void SkMatrix44::setIdentity() {
194 sk_bzero(fMat, sizeof(fMat));
195 fMat[0][0] = fMat[1][1] = fMat[2][2] = fMat[3][3] = 1;
reed@google.com7d683352012-12-03 21:19:52 +0000196 this->setTypeMask(kIdentity_Mask);
reed@google.com8260a892011-06-13 14:02:52 +0000197}
198
199void SkMatrix44::set3x3(SkMScalar m00, SkMScalar m01, SkMScalar m02,
200 SkMScalar m10, SkMScalar m11, SkMScalar m12,
201 SkMScalar m20, SkMScalar m21, SkMScalar m22) {
reed@google.com8260a892011-06-13 14:02:52 +0000202 fMat[0][0] = m00; fMat[0][1] = m01; fMat[0][2] = m02; fMat[0][3] = 0;
203 fMat[1][0] = m10; fMat[1][1] = m11; fMat[1][2] = m12; fMat[1][3] = 0;
204 fMat[2][0] = m20; fMat[2][1] = m21; fMat[2][2] = m22; fMat[2][3] = 0;
205 fMat[3][0] = 0; fMat[3][1] = 0; fMat[3][2] = 0; fMat[3][3] = 1;
reed@google.com7d683352012-12-03 21:19:52 +0000206 this->dirtyTypeMask();
reed@google.com8260a892011-06-13 14:02:52 +0000207}
208
209///////////////////////////////////////////////////////////////////////////////
210
reed@google.com99b5c7f2012-12-05 22:13:59 +0000211void SkMatrix44::setTranslate(SkMScalar dx, SkMScalar dy, SkMScalar dz) {
reed@google.com8260a892011-06-13 14:02:52 +0000212 this->setIdentity();
skia.committer@gmail.come659c2e2012-12-04 02:01:25 +0000213
reed@google.com99b5c7f2012-12-05 22:13:59 +0000214 if (!dx && !dy && !dz) {
215 return;
reed@google.com7d683352012-12-03 21:19:52 +0000216 }
skia.committer@gmail.com0264fb42012-12-06 02:01:25 +0000217
reed@google.com99b5c7f2012-12-05 22:13:59 +0000218 fMat[3][0] = dx;
219 fMat[3][1] = dy;
220 fMat[3][2] = dz;
221 this->setTypeMask(kTranslate_Mask);
reed@google.com8260a892011-06-13 14:02:52 +0000222}
223
224void SkMatrix44::preTranslate(SkMScalar dx, SkMScalar dy, SkMScalar dz) {
reed@google.com99b5c7f2012-12-05 22:13:59 +0000225 if (!dx && !dy && !dz) {
226 return;
227 }
228
229 const double X = SkMScalarToDouble(dx);
230 const double Y = SkMScalarToDouble(dy);
231 const double Z = SkMScalarToDouble(dz);
232
233 double tmp;
234 for (int i = 0; i < 4; ++i) {
235 tmp = fMat[0][i] * X + fMat[1][i] * Y + fMat[2][i] * Z + fMat[3][i];
236 fMat[3][i] = SkDoubleToMScalar(tmp);
237 }
238 this->dirtyTypeMask();
reed@google.com8260a892011-06-13 14:02:52 +0000239}
240
241void SkMatrix44::postTranslate(SkMScalar dx, SkMScalar dy, SkMScalar dz) {
reed@google.com99b5c7f2012-12-05 22:13:59 +0000242 if (!dx && !dy && !dz) {
243 return;
244 }
245
246 if (this->getType() & kPerspective_Mask) {
247 for (int i = 0; i < 4; ++i) {
248 fMat[i][0] += fMat[i][3] * dx;
249 fMat[i][1] += fMat[i][3] * dy;
250 fMat[i][2] += fMat[i][3] * dz;
251 }
252 } else {
253 fMat[3][0] += dx;
254 fMat[3][1] += dy;
255 fMat[3][2] += dz;
256 this->dirtyTypeMask();
257 }
reed@google.com8260a892011-06-13 14:02:52 +0000258}
259
260///////////////////////////////////////////////////////////////////////////////
261
262void SkMatrix44::setScale(SkMScalar sx, SkMScalar sy, SkMScalar sz) {
reed@google.com99b5c7f2012-12-05 22:13:59 +0000263 this->setIdentity();
264
265 if (1 == sx && 1 == sy && 1 == sz) {
266 return;
267 }
268
reed@google.com8260a892011-06-13 14:02:52 +0000269 fMat[0][0] = sx;
270 fMat[1][1] = sy;
271 fMat[2][2] = sz;
reed@google.com99b5c7f2012-12-05 22:13:59 +0000272 this->setTypeMask(kScale_Mask);
reed@google.com8260a892011-06-13 14:02:52 +0000273}
274
275void SkMatrix44::preScale(SkMScalar sx, SkMScalar sy, SkMScalar sz) {
reed@google.com99b5c7f2012-12-05 22:13:59 +0000276 if (1 == sx && 1 == sy && 1 == sz) {
277 return;
278 }
skia.committer@gmail.com0264fb42012-12-06 02:01:25 +0000279
shawnsingh@chromium.orgf81f97e2012-12-13 22:21:36 +0000280 // The implementation matrix * pureScale can be shortcut
281 // by knowing that pureScale components effectively scale
282 // the columns of the original matrix.
283 for (int i = 0; i < 4; i++) {
284 fMat[0][i] *= sx;
285 fMat[1][i] *= sy;
286 fMat[2][i] *= sz;
287 }
288 this->dirtyTypeMask();
reed@google.com8260a892011-06-13 14:02:52 +0000289}
290
291void SkMatrix44::postScale(SkMScalar sx, SkMScalar sy, SkMScalar sz) {
reed@google.com99b5c7f2012-12-05 22:13:59 +0000292 if (1 == sx && 1 == sy && 1 == sz) {
293 return;
294 }
skia.committer@gmail.com0264fb42012-12-06 02:01:25 +0000295
reed@google.com8260a892011-06-13 14:02:52 +0000296 for (int i = 0; i < 4; i++) {
297 fMat[i][0] *= sx;
298 fMat[i][1] *= sy;
299 fMat[i][2] *= sz;
300 }
reed@google.com7d683352012-12-03 21:19:52 +0000301 this->dirtyTypeMask();
reed@google.com8260a892011-06-13 14:02:52 +0000302}
303
304///////////////////////////////////////////////////////////////////////////////
305
306void SkMatrix44::setRotateAbout(SkMScalar x, SkMScalar y, SkMScalar z,
307 SkMScalar radians) {
reed@google.com7d683352012-12-03 21:19:52 +0000308 double len2 = (double)x * x + (double)y * y + (double)z * z;
309 if (1 != len2) {
310 if (0 == len2) {
reed@google.com8260a892011-06-13 14:02:52 +0000311 this->setIdentity();
312 return;
313 }
314 double scale = 1 / sqrt(len2);
bsalomon@google.com9d12f5c2011-09-29 18:08:18 +0000315 x = SkDoubleToMScalar(x * scale);
316 y = SkDoubleToMScalar(y * scale);
317 z = SkDoubleToMScalar(z * scale);
reed@google.com8260a892011-06-13 14:02:52 +0000318 }
319 this->setRotateAboutUnit(x, y, z, radians);
320}
321
322void SkMatrix44::setRotateAboutUnit(SkMScalar x, SkMScalar y, SkMScalar z,
323 SkMScalar radians) {
324 double c = cos(radians);
325 double s = sin(radians);
326 double C = 1 - c;
327 double xs = x * s;
328 double ys = y * s;
329 double zs = z * s;
330 double xC = x * C;
331 double yC = y * C;
332 double zC = z * C;
333 double xyC = x * yC;
334 double yzC = y * zC;
335 double zxC = z * xC;
336
337 // if you're looking at wikipedia, remember that we're column major.
bsalomon@google.com9d12f5c2011-09-29 18:08:18 +0000338 this->set3x3(SkDoubleToMScalar(x * xC + c), // scale x
339 SkDoubleToMScalar(xyC + zs), // skew x
340 SkDoubleToMScalar(zxC - ys), // trans x
341
342 SkDoubleToMScalar(xyC - zs), // skew y
343 SkDoubleToMScalar(y * yC + c), // scale y
344 SkDoubleToMScalar(yzC + xs), // trans y
345
346 SkDoubleToMScalar(zxC + ys), // persp x
347 SkDoubleToMScalar(yzC - xs), // persp y
348 SkDoubleToMScalar(z * zC + c)); // persp 2
reed@google.com8260a892011-06-13 14:02:52 +0000349}
350
351///////////////////////////////////////////////////////////////////////////////
352
reed@google.com99b5c7f2012-12-05 22:13:59 +0000353static bool bits_isonly(int value, int mask) {
354 return 0 == (value & ~mask);
355}
356
reed@google.com8260a892011-06-13 14:02:52 +0000357void SkMatrix44::setConcat(const SkMatrix44& a, const SkMatrix44& b) {
reed@google.com99b5c7f2012-12-05 22:13:59 +0000358 const SkMatrix44::TypeMask a_mask = a.getType();
359 const SkMatrix44::TypeMask b_mask = b.getType();
360
361 if (kIdentity_Mask == a_mask) {
reed@google.com7d683352012-12-03 21:19:52 +0000362 *this = b;
363 return;
364 }
reed@google.com99b5c7f2012-12-05 22:13:59 +0000365 if (kIdentity_Mask == b_mask) {
reed@google.com7d683352012-12-03 21:19:52 +0000366 *this = a;
367 return;
368 }
369
370 bool useStorage = (this == &a || this == &b);
371 SkMScalar storage[16];
372 SkMScalar* result = useStorage ? storage : &fMat[0][0];
373
reed@google.com99b5c7f2012-12-05 22:13:59 +0000374 if (bits_isonly(a_mask | b_mask, kScale_Mask | kTranslate_Mask)) {
375 sk_bzero(result, sizeof(storage));
376 result[0] = a.fMat[0][0] * b.fMat[0][0];
377 result[5] = a.fMat[1][1] * b.fMat[1][1];
378 result[10] = a.fMat[2][2] * b.fMat[2][2];
379 result[12] = a.fMat[0][0] * b.fMat[3][0] + a.fMat[3][0];
380 result[13] = a.fMat[1][1] * b.fMat[3][1] + a.fMat[3][1];
381 result[14] = a.fMat[2][2] * b.fMat[3][2] + a.fMat[3][2];
382 result[15] = 1;
383 } else {
384 for (int j = 0; j < 4; j++) {
385 for (int i = 0; i < 4; i++) {
386 double value = 0;
387 for (int k = 0; k < 4; k++) {
388 value += SkMScalarToDouble(a.fMat[k][i]) * b.fMat[j][k];
389 }
390 *result++ = SkDoubleToMScalar(value);
reed@google.com8260a892011-06-13 14:02:52 +0000391 }
reed@google.com8260a892011-06-13 14:02:52 +0000392 }
393 }
reed@google.com99b5c7f2012-12-05 22:13:59 +0000394
reed@google.com7d683352012-12-03 21:19:52 +0000395 if (useStorage) {
396 memcpy(fMat, storage, sizeof(storage));
397 }
reed@google.com7d683352012-12-03 21:19:52 +0000398 this->dirtyTypeMask();
reed@google.com8260a892011-06-13 14:02:52 +0000399}
400
401///////////////////////////////////////////////////////////////////////////////
402
403static inline SkMScalar det2x2(double m00, double m01, double m10, double m11) {
bsalomon@google.com9d12f5c2011-09-29 18:08:18 +0000404 return SkDoubleToMScalar(m00 * m11 - m10 * m01);
reed@google.com8260a892011-06-13 14:02:52 +0000405}
406
407static inline double det3x3(double m00, double m01, double m02,
408 double m10, double m11, double m12,
409 double m20, double m21, double m22) {
410 return m00 * det2x2(m11, m12, m21, m22) -
411 m10 * det2x2(m01, m02, m21, m22) +
412 m20 * det2x2(m01, m02, m11, m12);
413}
414
415/** We always perform the calculation in doubles, to avoid prematurely losing
416 precision along the way. This relies on the compiler automatically
417 promoting our SkMScalar values to double (if needed).
418 */
419double SkMatrix44::determinant() const {
mike@reedtribe.orgf8b1ebc2012-12-10 03:27:47 +0000420 if (this->isIdentity()) {
421 return 1;
422 }
423 if (this->isScaleTranslate()) {
424 return fMat[0][0] * fMat[1][1] * fMat[2][2] * fMat[3][3];
425 }
426
tomhudson@google.com9973a8a2012-12-13 09:55:42 +0000427 double a00 = fMat[0][0];
428 double a01 = fMat[0][1];
429 double a02 = fMat[0][2];
430 double a03 = fMat[0][3];
431 double a10 = fMat[1][0];
432 double a11 = fMat[1][1];
433 double a12 = fMat[1][2];
434 double a13 = fMat[1][3];
435 double a20 = fMat[2][0];
436 double a21 = fMat[2][1];
437 double a22 = fMat[2][2];
438 double a23 = fMat[2][3];
439 double a30 = fMat[3][0];
440 double a31 = fMat[3][1];
441 double a32 = fMat[3][2];
442 double a33 = fMat[3][3];
443
444 double b00 = a00 * a11 - a01 * a10;
445 double b01 = a00 * a12 - a02 * a10;
446 double b02 = a00 * a13 - a03 * a10;
447 double b03 = a01 * a12 - a02 * a11;
448 double b04 = a01 * a13 - a03 * a11;
449 double b05 = a02 * a13 - a03 * a12;
450 double b06 = a20 * a31 - a21 * a30;
451 double b07 = a20 * a32 - a22 * a30;
452 double b08 = a20 * a33 - a23 * a30;
453 double b09 = a21 * a32 - a22 * a31;
454 double b10 = a21 * a33 - a23 * a31;
455 double b11 = a22 * a33 - a23 * a32;
456
457 // Calculate the determinant
458 return b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
reed@google.com8260a892011-06-13 14:02:52 +0000459}
460
461///////////////////////////////////////////////////////////////////////////////
462
463// just picked a small value. not sure how to pick the "right" one
464#define TOO_SMALL_FOR_DETERMINANT (1.e-8)
465
466static inline double dabs(double x) {
467 if (x < 0) {
468 x = -x;
469 }
470 return x;
471}
472
473bool SkMatrix44::invert(SkMatrix44* inverse) const {
mike@reedtribe.orgf8b1ebc2012-12-10 03:27:47 +0000474 if (this->isIdentity()) {
reed@google.com7d683352012-12-03 21:19:52 +0000475 if (inverse) {
476 *inverse = *this;
477 return true;
478 }
479 }
mike@reedtribe.orgf8b1ebc2012-12-10 03:27:47 +0000480 if (this->isTranslate()) {
reed@google.com99b5c7f2012-12-05 22:13:59 +0000481 if (inverse) {
482 inverse->setTranslate(-fMat[3][0], -fMat[3][1], -fMat[3][2]);
483 }
484 return true;
485 }
mike@reedtribe.orgf8b1ebc2012-12-10 03:27:47 +0000486 if (this->isScaleTranslate()) {
reed@google.com99b5c7f2012-12-05 22:13:59 +0000487 if (0 == fMat[0][0] * fMat[1][1] * fMat[2][2]) {
488 return false;
489 }
490 if (inverse) {
491 sk_bzero(inverse->fMat, sizeof(inverse->fMat));
492
493 inverse->fMat[3][0] = -fMat[3][0] / fMat[0][0];
494 inverse->fMat[3][1] = -fMat[3][1] / fMat[1][1];
495 inverse->fMat[3][2] = -fMat[3][2] / fMat[2][2];
496
497 inverse->fMat[0][0] = 1 / fMat[0][0];
498 inverse->fMat[1][1] = 1 / fMat[1][1];
499 inverse->fMat[2][2] = 1 / fMat[2][2];
500 inverse->fMat[3][3] = 1;
501
mike@reedtribe.orgf8b1ebc2012-12-10 03:27:47 +0000502 inverse->setTypeMask(this->getType());
reed@google.com99b5c7f2012-12-05 22:13:59 +0000503 }
504 return true;
505 }
506
tomhudson@google.com9973a8a2012-12-13 09:55:42 +0000507 double a00 = fMat[0][0];
508 double a01 = fMat[0][1];
509 double a02 = fMat[0][2];
510 double a03 = fMat[0][3];
511 double a10 = fMat[1][0];
512 double a11 = fMat[1][1];
513 double a12 = fMat[1][2];
514 double a13 = fMat[1][3];
515 double a20 = fMat[2][0];
516 double a21 = fMat[2][1];
517 double a22 = fMat[2][2];
518 double a23 = fMat[2][3];
519 double a30 = fMat[3][0];
520 double a31 = fMat[3][1];
521 double a32 = fMat[3][2];
522 double a33 = fMat[3][3];
523
524 double b00 = a00 * a11 - a01 * a10;
525 double b01 = a00 * a12 - a02 * a10;
526 double b02 = a00 * a13 - a03 * a10;
527 double b03 = a01 * a12 - a02 * a11;
528 double b04 = a01 * a13 - a03 * a11;
529 double b05 = a02 * a13 - a03 * a12;
530 double b06 = a20 * a31 - a21 * a30;
531 double b07 = a20 * a32 - a22 * a30;
532 double b08 = a20 * a33 - a23 * a30;
533 double b09 = a21 * a32 - a22 * a31;
534 double b10 = a21 * a33 - a23 * a31;
535 double b11 = a22 * a33 - a23 * a32;
536
537 // Calculate the determinant
538 double det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
539
reed@google.com8260a892011-06-13 14:02:52 +0000540 if (dabs(det) < TOO_SMALL_FOR_DETERMINANT) {
541 return false;
542 }
543 if (NULL == inverse) {
544 return true;
545 }
tomhudson@google.com9973a8a2012-12-13 09:55:42 +0000546 double invdet = 1.0 / det;
reed@google.com8260a892011-06-13 14:02:52 +0000547
tomhudson@google.com9973a8a2012-12-13 09:55:42 +0000548 b00 *= invdet;
549 b01 *= invdet;
550 b02 *= invdet;
551 b03 *= invdet;
552 b04 *= invdet;
553 b05 *= invdet;
554 b06 *= invdet;
555 b07 *= invdet;
556 b08 *= invdet;
557 b09 *= invdet;
558 b10 *= invdet;
559 b11 *= invdet;
reed@google.com8260a892011-06-13 14:02:52 +0000560
tomhudson@google.com9973a8a2012-12-13 09:55:42 +0000561 inverse->fMat[0][0] = SkDoubleToMScalar(a11 * b11 - a12 * b10 + a13 * b09);
562 inverse->fMat[0][1] = SkDoubleToMScalar(a02 * b10 - a01 * b11 - a03 * b09);
563 inverse->fMat[0][2] = SkDoubleToMScalar(a31 * b05 - a32 * b04 + a33 * b03);
564 inverse->fMat[0][3] = SkDoubleToMScalar(a22 * b04 - a21 * b05 - a23 * b03);
565 inverse->fMat[1][0] = SkDoubleToMScalar(a12 * b08 - a10 * b11 - a13 * b07);
566 inverse->fMat[1][1] = SkDoubleToMScalar(a00 * b11 - a02 * b08 + a03 * b07);
567 inverse->fMat[1][2] = SkDoubleToMScalar(a32 * b02 - a30 * b05 - a33 * b01);
568 inverse->fMat[1][3] = SkDoubleToMScalar(a20 * b05 - a22 * b02 + a23 * b01);
569 inverse->fMat[2][0] = SkDoubleToMScalar(a10 * b10 - a11 * b08 + a13 * b06);
570 inverse->fMat[2][1] = SkDoubleToMScalar(a01 * b08 - a00 * b10 - a03 * b06);
571 inverse->fMat[2][2] = SkDoubleToMScalar(a30 * b04 - a31 * b02 + a33 * b00);
572 inverse->fMat[2][3] = SkDoubleToMScalar(a21 * b02 - a20 * b04 - a23 * b00);
573 inverse->fMat[3][0] = SkDoubleToMScalar(a11 * b07 - a10 * b09 - a12 * b06);
574 inverse->fMat[3][1] = SkDoubleToMScalar(a00 * b09 - a01 * b07 + a02 * b06);
575 inverse->fMat[3][2] = SkDoubleToMScalar(a31 * b01 - a30 * b03 - a32 * b00);
576 inverse->fMat[3][3] = SkDoubleToMScalar(a20 * b03 - a21 * b01 + a22 * b00);
577 inverse->dirtyTypeMask();
reed@google.com8260a892011-06-13 14:02:52 +0000578
reed@google.com7d683352012-12-03 21:19:52 +0000579 inverse->dirtyTypeMask();
reed@google.com8260a892011-06-13 14:02:52 +0000580 return true;
581}
582
583///////////////////////////////////////////////////////////////////////////////
584
vollick@chromium.org9b21c252012-11-14 21:33:55 +0000585void SkMatrix44::transpose() {
586 SkTSwap(fMat[0][1], fMat[1][0]);
587 SkTSwap(fMat[0][2], fMat[2][0]);
588 SkTSwap(fMat[0][3], fMat[3][0]);
589 SkTSwap(fMat[1][2], fMat[2][1]);
590 SkTSwap(fMat[1][3], fMat[3][1]);
591 SkTSwap(fMat[2][3], fMat[3][2]);
reed@google.com7d683352012-12-03 21:19:52 +0000592
593 if (!this->isTriviallyIdentity()) {
594 this->dirtyTypeMask();
595 }
vollick@chromium.org9b21c252012-11-14 21:33:55 +0000596}
597
598///////////////////////////////////////////////////////////////////////////////
599
reed@google.com1ea95be2012-11-09 21:39:48 +0000600void SkMatrix44::mapScalars(const SkScalar src[4], SkScalar dst[4]) const {
reed@google.com7d683352012-12-03 21:19:52 +0000601 SkScalar storage[4];
602 SkScalar* result = (src == dst) ? storage : dst;
603
reed@google.com8260a892011-06-13 14:02:52 +0000604 for (int i = 0; i < 4; i++) {
605 SkMScalar value = 0;
606 for (int j = 0; j < 4; j++) {
607 value += fMat[j][i] * src[j];
608 }
bsalomon@google.com72e49b82011-10-27 21:47:03 +0000609 result[i] = SkMScalarToScalar(value);
reed@google.com8260a892011-06-13 14:02:52 +0000610 }
skia.committer@gmail.com0264fb42012-12-06 02:01:25 +0000611
reed@google.com7d683352012-12-03 21:19:52 +0000612 if (storage == result) {
613 memcpy(dst, storage, sizeof(storage));
614 }
reed@google.com8260a892011-06-13 14:02:52 +0000615}
616
reed@google.com1ea95be2012-11-09 21:39:48 +0000617#ifdef SK_MSCALAR_IS_DOUBLE
reed@google.com7d683352012-12-03 21:19:52 +0000618
reed@google.com1ea95be2012-11-09 21:39:48 +0000619void SkMatrix44::mapMScalars(const SkMScalar src[4], SkMScalar dst[4]) const {
reed@google.com7d683352012-12-03 21:19:52 +0000620 SkMScalar storage[4];
621 SkMScalar* result = (src == dst) ? storage : dst;
skia.committer@gmail.com0264fb42012-12-06 02:01:25 +0000622
reed@google.com1ea95be2012-11-09 21:39:48 +0000623 for (int i = 0; i < 4; i++) {
624 SkMScalar value = 0;
625 for (int j = 0; j < 4; j++) {
626 value += fMat[j][i] * src[j];
627 }
reed@google.com7d683352012-12-03 21:19:52 +0000628 result[i] = value;
reed@google.com1ea95be2012-11-09 21:39:48 +0000629 }
skia.committer@gmail.com0264fb42012-12-06 02:01:25 +0000630
reed@google.com7d683352012-12-03 21:19:52 +0000631 if (storage == result) {
632 memcpy(dst, storage, sizeof(storage));
633 }
reed@google.com1ea95be2012-11-09 21:39:48 +0000634}
reed@google.com7d683352012-12-03 21:19:52 +0000635
reed@google.com1ea95be2012-11-09 21:39:48 +0000636#endif
637
reed@google.com99b5c7f2012-12-05 22:13:59 +0000638typedef void (*Map2Procf)(const SkMScalar mat[][4], const float src2[], int count, float dst4[]);
639typedef void (*Map2Procd)(const SkMScalar mat[][4], const double src2[], int count, double dst4[]);
640
641static void map2_if(const SkMScalar mat[][4], const float* SK_RESTRICT src2,
642 int count, float* SK_RESTRICT dst4) {
643 for (int i = 0; i < count; ++i) {
644 dst4[0] = src2[0];
645 dst4[1] = src2[1];
646 dst4[2] = 0;
647 dst4[3] = 1;
648 src2 += 2;
649 dst4 += 4;
650 }
651}
652
653static void map2_id(const SkMScalar mat[][4], const double* SK_RESTRICT src2,
654 int count, double* SK_RESTRICT dst4) {
655 for (int i = 0; i < count; ++i) {
656 dst4[0] = src2[0];
657 dst4[1] = src2[1];
658 dst4[2] = 0;
659 dst4[3] = 1;
660 src2 += 2;
661 dst4 += 4;
662 }
663}
664
665static void map2_tf(const SkMScalar mat[][4], const float* SK_RESTRICT src2,
666 int count, float* SK_RESTRICT dst4) {
667 const float mat30 = SkMScalarToFloat(mat[3][0]);
668 const float mat31 = SkMScalarToFloat(mat[3][1]);
669 const float mat32 = SkMScalarToFloat(mat[3][2]);
670 for (int n = 0; n < count; ++n) {
671 dst4[0] = src2[0] + mat30;
672 dst4[1] = src2[1] + mat31;
673 dst4[2] = mat32;
674 dst4[3] = 1;
675 src2 += 2;
676 dst4 += 4;
677 }
678}
679
680static void map2_td(const SkMScalar mat[][4], const double* SK_RESTRICT src2,
681 int count, double* SK_RESTRICT dst4) {
682 for (int n = 0; n < count; ++n) {
683 dst4[0] = src2[0] + mat[3][0];
684 dst4[1] = src2[1] + mat[3][1];
685 dst4[2] = mat[3][2];
686 dst4[3] = 1;
687 src2 += 2;
688 dst4 += 4;
689 }
690}
691
692static void map2_sf(const SkMScalar mat[][4], const float* SK_RESTRICT src2,
693 int count, float* SK_RESTRICT dst4) {
694 const float mat32 = SkMScalarToFloat(mat[3][2]);
695 for (int n = 0; n < count; ++n) {
696 dst4[0] = SkMScalarToFloat(mat[0][0] * src2[0] + mat[3][0]);
697 dst4[1] = SkMScalarToFloat(mat[1][1] * src2[1] + mat[3][1]);
698 dst4[2] = mat32;
699 dst4[3] = 1;
700 src2 += 2;
701 dst4 += 4;
702 }
703}
704
705static void map2_sd(const SkMScalar mat[][4], const double* SK_RESTRICT src2,
706 int count, double* SK_RESTRICT dst4) {
707 for (int n = 0; n < count; ++n) {
708 dst4[0] = mat[0][0] * src2[0] + mat[3][0];
709 dst4[1] = mat[1][1] * src2[1] + mat[3][1];
710 dst4[2] = mat[3][2];
711 dst4[3] = 1;
712 src2 += 2;
713 dst4 += 4;
714 }
715}
716
717static void map2_af(const SkMScalar mat[][4], const float* SK_RESTRICT src2,
718 int count, float* SK_RESTRICT dst4) {
719 double r;
720 for (int n = 0; n < count; ++n) {
721 double sx = src2[0];
722 double sy = src2[1];
723 r = mat[0][0] * sx + mat[1][0] * sy + mat[3][0];
724 dst4[0] = SkMScalarToFloat(r);
725 r = mat[0][1] * sx + mat[1][1] * sy + mat[3][1];
726 dst4[1] = SkMScalarToFloat(r);
727 r = mat[0][2] * sx + mat[1][2] * sy + mat[3][2];
728 dst4[2] = SkMScalarToFloat(r);
729 dst4[3] = 1;
730 src2 += 2;
731 dst4 += 4;
732 }
733}
734
735static void map2_ad(const SkMScalar mat[][4], const double* SK_RESTRICT src2,
736 int count, double* SK_RESTRICT dst4) {
737 for (int n = 0; n < count; ++n) {
738 double sx = src2[0];
739 double sy = src2[1];
740 dst4[0] = mat[0][0] * sx + mat[1][0] * sy + mat[3][0];
741 dst4[1] = mat[0][1] * sx + mat[1][1] * sy + mat[3][1];
742 dst4[2] = mat[0][2] * sx + mat[1][2] * sy + mat[3][2];
743 dst4[3] = 1;
744 src2 += 2;
745 dst4 += 4;
746 }
747}
748
749static void map2_pf(const SkMScalar mat[][4], const float* SK_RESTRICT src2,
750 int count, float* SK_RESTRICT dst4) {
751 double r;
752 for (int n = 0; n < count; ++n) {
753 double sx = src2[0];
754 double sy = src2[1];
755 for (int i = 0; i < 4; i++) {
756 r = mat[0][i] * sx + mat[1][i] * sy + mat[3][i];
757 dst4[i] = SkMScalarToFloat(r);
758 }
759 src2 += 2;
760 dst4 += 4;
761 }
762}
763
764static void map2_pd(const SkMScalar mat[][4], const double* SK_RESTRICT src2,
765 int count, double* SK_RESTRICT dst4) {
766 for (int n = 0; n < count; ++n) {
767 double sx = src2[0];
768 double sy = src2[1];
769 for (int i = 0; i < 4; i++) {
770 dst4[i] = mat[0][i] * sx + mat[1][i] * sy + mat[3][i];
771 }
772 src2 += 2;
773 dst4 += 4;
774 }
775}
776
777void SkMatrix44::map2(const float src2[], int count, float dst4[]) const {
778 static const Map2Procf gProc[] = {
779 map2_if, map2_tf, map2_sf, map2_sf, map2_af, map2_af, map2_af, map2_af
780 };
781
782 TypeMask mask = this->getType();
783 Map2Procf proc = (mask & kPerspective_Mask) ? map2_pf : gProc[mask];
784 proc(fMat, src2, count, dst4);
785}
786
787void SkMatrix44::map2(const double src2[], int count, double dst4[]) const {
788 static const Map2Procd gProc[] = {
789 map2_id, map2_td, map2_sd, map2_sd, map2_ad, map2_ad, map2_ad, map2_ad
790 };
skia.committer@gmail.com0264fb42012-12-06 02:01:25 +0000791
reed@google.com99b5c7f2012-12-05 22:13:59 +0000792 TypeMask mask = this->getType();
793 Map2Procd proc = (mask & kPerspective_Mask) ? map2_pd : gProc[mask];
794 proc(fMat, src2, count, dst4);
795}
796
reed@google.com8260a892011-06-13 14:02:52 +0000797///////////////////////////////////////////////////////////////////////////////
798
799void SkMatrix44::dump() const {
tomhudson@google.com9ac4a892011-06-28 13:53:13 +0000800 static const char* format =
801 "[%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 +0000802#if 0
tomhudson@google.com9ac4a892011-06-28 13:53:13 +0000803 SkDebugf(format,
reed@google.com8260a892011-06-13 14:02:52 +0000804 fMat[0][0], fMat[1][0], fMat[2][0], fMat[3][0],
805 fMat[0][1], fMat[1][1], fMat[2][1], fMat[3][1],
806 fMat[0][2], fMat[1][2], fMat[2][2], fMat[3][2],
807 fMat[0][3], fMat[1][3], fMat[2][3], fMat[3][3]);
tomhudson@google.com9ac4a892011-06-28 13:53:13 +0000808#else
809 SkDebugf(format,
810 fMat[0][0], fMat[0][1], fMat[0][2], fMat[0][3],
811 fMat[1][0], fMat[1][1], fMat[1][2], fMat[1][3],
812 fMat[2][0], fMat[2][1], fMat[2][2], fMat[2][3],
813 fMat[3][0], fMat[3][1], fMat[3][2], fMat[3][3]);
reed@google.com8260a892011-06-13 14:02:52 +0000814#endif
815}
816
817///////////////////////////////////////////////////////////////////////////////
818
reed@google.com7d683352012-12-03 21:19:52 +0000819// TODO: make this support src' perspective elements
820//
reed@google.com8260a892011-06-13 14:02:52 +0000821static void initFromMatrix(SkMScalar dst[4][4], const SkMatrix& src) {
822 sk_bzero(dst, 16 * sizeof(SkMScalar));
bsalomon@google.com72e49b82011-10-27 21:47:03 +0000823 dst[0][0] = SkScalarToMScalar(src[SkMatrix::kMScaleX]);
824 dst[1][0] = SkScalarToMScalar(src[SkMatrix::kMSkewX]);
825 dst[3][0] = SkScalarToMScalar(src[SkMatrix::kMTransX]);
826 dst[0][1] = SkScalarToMScalar(src[SkMatrix::kMSkewY]);
827 dst[1][1] = SkScalarToMScalar(src[SkMatrix::kMScaleY]);
828 dst[3][1] = SkScalarToMScalar(src[SkMatrix::kMTransY]);
reed@google.com8260a892011-06-13 14:02:52 +0000829 dst[2][2] = dst[3][3] = 1;
830}
831
832SkMatrix44::SkMatrix44(const SkMatrix& src) {
833 initFromMatrix(fMat, src);
834}
835
836SkMatrix44& SkMatrix44::operator=(const SkMatrix& src) {
837 initFromMatrix(fMat, src);
reed@google.com7d683352012-12-03 21:19:52 +0000838
839 if (src.isIdentity()) {
840 this->setTypeMask(kIdentity_Mask);
841 } else {
842 this->dirtyTypeMask();
843 }
reed@google.com8260a892011-06-13 14:02:52 +0000844 return *this;
845}
846
reed@google.com7d683352012-12-03 21:19:52 +0000847// TODO: make this support our perspective elements
848//
reed@google.com8260a892011-06-13 14:02:52 +0000849SkMatrix44::operator SkMatrix() const {
850 SkMatrix dst;
851 dst.reset(); // setup our perspective correctly for identity
852
bsalomon@google.com72e49b82011-10-27 21:47:03 +0000853 dst[SkMatrix::kMScaleX] = SkMScalarToScalar(fMat[0][0]);
854 dst[SkMatrix::kMSkewX] = SkMScalarToScalar(fMat[1][0]);
855 dst[SkMatrix::kMTransX] = SkMScalarToScalar(fMat[3][0]);
reed@google.com8260a892011-06-13 14:02:52 +0000856
bsalomon@google.com72e49b82011-10-27 21:47:03 +0000857 dst[SkMatrix::kMSkewY] = SkMScalarToScalar(fMat[0][1]);
858 dst[SkMatrix::kMScaleY] = SkMScalarToScalar(fMat[1][1]);
859 dst[SkMatrix::kMTransY] = SkMScalarToScalar(fMat[3][1]);
reed@google.com8260a892011-06-13 14:02:52 +0000860
861 return dst;
862}