blob: acd4ae6f8959b1749b42a816c266d4489b569d5f [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
reed@google.com1adad342012-12-10 21:21:27 +0000280 SkMatrix44 tmp(kUninitialized_Constructor);
reed@google.com8260a892011-06-13 14:02:52 +0000281 tmp.setScale(sx, sy, sz);
282 this->preConcat(tmp);
283}
284
285void SkMatrix44::postScale(SkMScalar sx, SkMScalar sy, SkMScalar sz) {
reed@google.com99b5c7f2012-12-05 22:13:59 +0000286 if (1 == sx && 1 == sy && 1 == sz) {
287 return;
288 }
skia.committer@gmail.com0264fb42012-12-06 02:01:25 +0000289
reed@google.com8260a892011-06-13 14:02:52 +0000290 for (int i = 0; i < 4; i++) {
291 fMat[i][0] *= sx;
292 fMat[i][1] *= sy;
293 fMat[i][2] *= sz;
294 }
reed@google.com7d683352012-12-03 21:19:52 +0000295 this->dirtyTypeMask();
reed@google.com8260a892011-06-13 14:02:52 +0000296}
297
298///////////////////////////////////////////////////////////////////////////////
299
300void SkMatrix44::setRotateAbout(SkMScalar x, SkMScalar y, SkMScalar z,
301 SkMScalar radians) {
reed@google.com7d683352012-12-03 21:19:52 +0000302 double len2 = (double)x * x + (double)y * y + (double)z * z;
303 if (1 != len2) {
304 if (0 == len2) {
reed@google.com8260a892011-06-13 14:02:52 +0000305 this->setIdentity();
306 return;
307 }
308 double scale = 1 / sqrt(len2);
bsalomon@google.com9d12f5c2011-09-29 18:08:18 +0000309 x = SkDoubleToMScalar(x * scale);
310 y = SkDoubleToMScalar(y * scale);
311 z = SkDoubleToMScalar(z * scale);
reed@google.com8260a892011-06-13 14:02:52 +0000312 }
313 this->setRotateAboutUnit(x, y, z, radians);
314}
315
316void SkMatrix44::setRotateAboutUnit(SkMScalar x, SkMScalar y, SkMScalar z,
317 SkMScalar radians) {
318 double c = cos(radians);
319 double s = sin(radians);
320 double C = 1 - c;
321 double xs = x * s;
322 double ys = y * s;
323 double zs = z * s;
324 double xC = x * C;
325 double yC = y * C;
326 double zC = z * C;
327 double xyC = x * yC;
328 double yzC = y * zC;
329 double zxC = z * xC;
330
331 // if you're looking at wikipedia, remember that we're column major.
bsalomon@google.com9d12f5c2011-09-29 18:08:18 +0000332 this->set3x3(SkDoubleToMScalar(x * xC + c), // scale x
333 SkDoubleToMScalar(xyC + zs), // skew x
334 SkDoubleToMScalar(zxC - ys), // trans x
335
336 SkDoubleToMScalar(xyC - zs), // skew y
337 SkDoubleToMScalar(y * yC + c), // scale y
338 SkDoubleToMScalar(yzC + xs), // trans y
339
340 SkDoubleToMScalar(zxC + ys), // persp x
341 SkDoubleToMScalar(yzC - xs), // persp y
342 SkDoubleToMScalar(z * zC + c)); // persp 2
reed@google.com8260a892011-06-13 14:02:52 +0000343}
344
345///////////////////////////////////////////////////////////////////////////////
346
reed@google.com99b5c7f2012-12-05 22:13:59 +0000347static bool bits_isonly(int value, int mask) {
348 return 0 == (value & ~mask);
349}
350
reed@google.com8260a892011-06-13 14:02:52 +0000351void SkMatrix44::setConcat(const SkMatrix44& a, const SkMatrix44& b) {
reed@google.com99b5c7f2012-12-05 22:13:59 +0000352 const SkMatrix44::TypeMask a_mask = a.getType();
353 const SkMatrix44::TypeMask b_mask = b.getType();
354
355 if (kIdentity_Mask == a_mask) {
reed@google.com7d683352012-12-03 21:19:52 +0000356 *this = b;
357 return;
358 }
reed@google.com99b5c7f2012-12-05 22:13:59 +0000359 if (kIdentity_Mask == b_mask) {
reed@google.com7d683352012-12-03 21:19:52 +0000360 *this = a;
361 return;
362 }
363
364 bool useStorage = (this == &a || this == &b);
365 SkMScalar storage[16];
366 SkMScalar* result = useStorage ? storage : &fMat[0][0];
367
reed@google.com99b5c7f2012-12-05 22:13:59 +0000368 if (bits_isonly(a_mask | b_mask, kScale_Mask | kTranslate_Mask)) {
369 sk_bzero(result, sizeof(storage));
370 result[0] = a.fMat[0][0] * b.fMat[0][0];
371 result[5] = a.fMat[1][1] * b.fMat[1][1];
372 result[10] = a.fMat[2][2] * b.fMat[2][2];
373 result[12] = a.fMat[0][0] * b.fMat[3][0] + a.fMat[3][0];
374 result[13] = a.fMat[1][1] * b.fMat[3][1] + a.fMat[3][1];
375 result[14] = a.fMat[2][2] * b.fMat[3][2] + a.fMat[3][2];
376 result[15] = 1;
377 } else {
378 for (int j = 0; j < 4; j++) {
379 for (int i = 0; i < 4; i++) {
380 double value = 0;
381 for (int k = 0; k < 4; k++) {
382 value += SkMScalarToDouble(a.fMat[k][i]) * b.fMat[j][k];
383 }
384 *result++ = SkDoubleToMScalar(value);
reed@google.com8260a892011-06-13 14:02:52 +0000385 }
reed@google.com8260a892011-06-13 14:02:52 +0000386 }
387 }
reed@google.com99b5c7f2012-12-05 22:13:59 +0000388
reed@google.com7d683352012-12-03 21:19:52 +0000389 if (useStorage) {
390 memcpy(fMat, storage, sizeof(storage));
391 }
reed@google.com7d683352012-12-03 21:19:52 +0000392 this->dirtyTypeMask();
reed@google.com8260a892011-06-13 14:02:52 +0000393}
394
395///////////////////////////////////////////////////////////////////////////////
396
397static inline SkMScalar det2x2(double m00, double m01, double m10, double m11) {
bsalomon@google.com9d12f5c2011-09-29 18:08:18 +0000398 return SkDoubleToMScalar(m00 * m11 - m10 * m01);
reed@google.com8260a892011-06-13 14:02:52 +0000399}
400
401static inline double det3x3(double m00, double m01, double m02,
402 double m10, double m11, double m12,
403 double m20, double m21, double m22) {
404 return m00 * det2x2(m11, m12, m21, m22) -
405 m10 * det2x2(m01, m02, m21, m22) +
406 m20 * det2x2(m01, m02, m11, m12);
407}
408
409/** We always perform the calculation in doubles, to avoid prematurely losing
410 precision along the way. This relies on the compiler automatically
411 promoting our SkMScalar values to double (if needed).
412 */
413double SkMatrix44::determinant() const {
mike@reedtribe.orgf8b1ebc2012-12-10 03:27:47 +0000414 if (this->isIdentity()) {
415 return 1;
416 }
417 if (this->isScaleTranslate()) {
418 return fMat[0][0] * fMat[1][1] * fMat[2][2] * fMat[3][3];
419 }
420
tomhudson@google.com9973a8a2012-12-13 09:55:42 +0000421 double a00 = fMat[0][0];
422 double a01 = fMat[0][1];
423 double a02 = fMat[0][2];
424 double a03 = fMat[0][3];
425 double a10 = fMat[1][0];
426 double a11 = fMat[1][1];
427 double a12 = fMat[1][2];
428 double a13 = fMat[1][3];
429 double a20 = fMat[2][0];
430 double a21 = fMat[2][1];
431 double a22 = fMat[2][2];
432 double a23 = fMat[2][3];
433 double a30 = fMat[3][0];
434 double a31 = fMat[3][1];
435 double a32 = fMat[3][2];
436 double a33 = fMat[3][3];
437
438 double b00 = a00 * a11 - a01 * a10;
439 double b01 = a00 * a12 - a02 * a10;
440 double b02 = a00 * a13 - a03 * a10;
441 double b03 = a01 * a12 - a02 * a11;
442 double b04 = a01 * a13 - a03 * a11;
443 double b05 = a02 * a13 - a03 * a12;
444 double b06 = a20 * a31 - a21 * a30;
445 double b07 = a20 * a32 - a22 * a30;
446 double b08 = a20 * a33 - a23 * a30;
447 double b09 = a21 * a32 - a22 * a31;
448 double b10 = a21 * a33 - a23 * a31;
449 double b11 = a22 * a33 - a23 * a32;
450
451 // Calculate the determinant
452 return b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
reed@google.com8260a892011-06-13 14:02:52 +0000453}
454
455///////////////////////////////////////////////////////////////////////////////
456
457// just picked a small value. not sure how to pick the "right" one
458#define TOO_SMALL_FOR_DETERMINANT (1.e-8)
459
460static inline double dabs(double x) {
461 if (x < 0) {
462 x = -x;
463 }
464 return x;
465}
466
467bool SkMatrix44::invert(SkMatrix44* inverse) const {
mike@reedtribe.orgf8b1ebc2012-12-10 03:27:47 +0000468 if (this->isIdentity()) {
reed@google.com7d683352012-12-03 21:19:52 +0000469 if (inverse) {
470 *inverse = *this;
471 return true;
472 }
473 }
mike@reedtribe.orgf8b1ebc2012-12-10 03:27:47 +0000474 if (this->isTranslate()) {
reed@google.com99b5c7f2012-12-05 22:13:59 +0000475 if (inverse) {
476 inverse->setTranslate(-fMat[3][0], -fMat[3][1], -fMat[3][2]);
477 }
478 return true;
479 }
mike@reedtribe.orgf8b1ebc2012-12-10 03:27:47 +0000480 if (this->isScaleTranslate()) {
reed@google.com99b5c7f2012-12-05 22:13:59 +0000481 if (0 == fMat[0][0] * fMat[1][1] * fMat[2][2]) {
482 return false;
483 }
484 if (inverse) {
485 sk_bzero(inverse->fMat, sizeof(inverse->fMat));
486
487 inverse->fMat[3][0] = -fMat[3][0] / fMat[0][0];
488 inverse->fMat[3][1] = -fMat[3][1] / fMat[1][1];
489 inverse->fMat[3][2] = -fMat[3][2] / fMat[2][2];
490
491 inverse->fMat[0][0] = 1 / fMat[0][0];
492 inverse->fMat[1][1] = 1 / fMat[1][1];
493 inverse->fMat[2][2] = 1 / fMat[2][2];
494 inverse->fMat[3][3] = 1;
495
mike@reedtribe.orgf8b1ebc2012-12-10 03:27:47 +0000496 inverse->setTypeMask(this->getType());
reed@google.com99b5c7f2012-12-05 22:13:59 +0000497 }
498 return true;
499 }
500
tomhudson@google.com9973a8a2012-12-13 09:55:42 +0000501 double a00 = fMat[0][0];
502 double a01 = fMat[0][1];
503 double a02 = fMat[0][2];
504 double a03 = fMat[0][3];
505 double a10 = fMat[1][0];
506 double a11 = fMat[1][1];
507 double a12 = fMat[1][2];
508 double a13 = fMat[1][3];
509 double a20 = fMat[2][0];
510 double a21 = fMat[2][1];
511 double a22 = fMat[2][2];
512 double a23 = fMat[2][3];
513 double a30 = fMat[3][0];
514 double a31 = fMat[3][1];
515 double a32 = fMat[3][2];
516 double a33 = fMat[3][3];
517
518 double b00 = a00 * a11 - a01 * a10;
519 double b01 = a00 * a12 - a02 * a10;
520 double b02 = a00 * a13 - a03 * a10;
521 double b03 = a01 * a12 - a02 * a11;
522 double b04 = a01 * a13 - a03 * a11;
523 double b05 = a02 * a13 - a03 * a12;
524 double b06 = a20 * a31 - a21 * a30;
525 double b07 = a20 * a32 - a22 * a30;
526 double b08 = a20 * a33 - a23 * a30;
527 double b09 = a21 * a32 - a22 * a31;
528 double b10 = a21 * a33 - a23 * a31;
529 double b11 = a22 * a33 - a23 * a32;
530
531 // Calculate the determinant
532 double det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
533
reed@google.com8260a892011-06-13 14:02:52 +0000534 if (dabs(det) < TOO_SMALL_FOR_DETERMINANT) {
535 return false;
536 }
537 if (NULL == inverse) {
538 return true;
539 }
tomhudson@google.com9973a8a2012-12-13 09:55:42 +0000540 double invdet = 1.0 / det;
reed@google.com8260a892011-06-13 14:02:52 +0000541
tomhudson@google.com9973a8a2012-12-13 09:55:42 +0000542 b00 *= invdet;
543 b01 *= invdet;
544 b02 *= invdet;
545 b03 *= invdet;
546 b04 *= invdet;
547 b05 *= invdet;
548 b06 *= invdet;
549 b07 *= invdet;
550 b08 *= invdet;
551 b09 *= invdet;
552 b10 *= invdet;
553 b11 *= invdet;
reed@google.com8260a892011-06-13 14:02:52 +0000554
tomhudson@google.com9973a8a2012-12-13 09:55:42 +0000555 inverse->fMat[0][0] = SkDoubleToMScalar(a11 * b11 - a12 * b10 + a13 * b09);
556 inverse->fMat[0][1] = SkDoubleToMScalar(a02 * b10 - a01 * b11 - a03 * b09);
557 inverse->fMat[0][2] = SkDoubleToMScalar(a31 * b05 - a32 * b04 + a33 * b03);
558 inverse->fMat[0][3] = SkDoubleToMScalar(a22 * b04 - a21 * b05 - a23 * b03);
559 inverse->fMat[1][0] = SkDoubleToMScalar(a12 * b08 - a10 * b11 - a13 * b07);
560 inverse->fMat[1][1] = SkDoubleToMScalar(a00 * b11 - a02 * b08 + a03 * b07);
561 inverse->fMat[1][2] = SkDoubleToMScalar(a32 * b02 - a30 * b05 - a33 * b01);
562 inverse->fMat[1][3] = SkDoubleToMScalar(a20 * b05 - a22 * b02 + a23 * b01);
563 inverse->fMat[2][0] = SkDoubleToMScalar(a10 * b10 - a11 * b08 + a13 * b06);
564 inverse->fMat[2][1] = SkDoubleToMScalar(a01 * b08 - a00 * b10 - a03 * b06);
565 inverse->fMat[2][2] = SkDoubleToMScalar(a30 * b04 - a31 * b02 + a33 * b00);
566 inverse->fMat[2][3] = SkDoubleToMScalar(a21 * b02 - a20 * b04 - a23 * b00);
567 inverse->fMat[3][0] = SkDoubleToMScalar(a11 * b07 - a10 * b09 - a12 * b06);
568 inverse->fMat[3][1] = SkDoubleToMScalar(a00 * b09 - a01 * b07 + a02 * b06);
569 inverse->fMat[3][2] = SkDoubleToMScalar(a31 * b01 - a30 * b03 - a32 * b00);
570 inverse->fMat[3][3] = SkDoubleToMScalar(a20 * b03 - a21 * b01 + a22 * b00);
571 inverse->dirtyTypeMask();
reed@google.com8260a892011-06-13 14:02:52 +0000572
reed@google.com7d683352012-12-03 21:19:52 +0000573 inverse->dirtyTypeMask();
reed@google.com8260a892011-06-13 14:02:52 +0000574 return true;
575}
576
577///////////////////////////////////////////////////////////////////////////////
578
vollick@chromium.org9b21c252012-11-14 21:33:55 +0000579void SkMatrix44::transpose() {
580 SkTSwap(fMat[0][1], fMat[1][0]);
581 SkTSwap(fMat[0][2], fMat[2][0]);
582 SkTSwap(fMat[0][3], fMat[3][0]);
583 SkTSwap(fMat[1][2], fMat[2][1]);
584 SkTSwap(fMat[1][3], fMat[3][1]);
585 SkTSwap(fMat[2][3], fMat[3][2]);
reed@google.com7d683352012-12-03 21:19:52 +0000586
587 if (!this->isTriviallyIdentity()) {
588 this->dirtyTypeMask();
589 }
vollick@chromium.org9b21c252012-11-14 21:33:55 +0000590}
591
592///////////////////////////////////////////////////////////////////////////////
593
reed@google.com1ea95be2012-11-09 21:39:48 +0000594void SkMatrix44::mapScalars(const SkScalar src[4], SkScalar dst[4]) const {
reed@google.com7d683352012-12-03 21:19:52 +0000595 SkScalar storage[4];
596 SkScalar* result = (src == dst) ? storage : dst;
597
reed@google.com8260a892011-06-13 14:02:52 +0000598 for (int i = 0; i < 4; i++) {
599 SkMScalar value = 0;
600 for (int j = 0; j < 4; j++) {
601 value += fMat[j][i] * src[j];
602 }
bsalomon@google.com72e49b82011-10-27 21:47:03 +0000603 result[i] = SkMScalarToScalar(value);
reed@google.com8260a892011-06-13 14:02:52 +0000604 }
skia.committer@gmail.com0264fb42012-12-06 02:01:25 +0000605
reed@google.com7d683352012-12-03 21:19:52 +0000606 if (storage == result) {
607 memcpy(dst, storage, sizeof(storage));
608 }
reed@google.com8260a892011-06-13 14:02:52 +0000609}
610
reed@google.com1ea95be2012-11-09 21:39:48 +0000611#ifdef SK_MSCALAR_IS_DOUBLE
reed@google.com7d683352012-12-03 21:19:52 +0000612
reed@google.com1ea95be2012-11-09 21:39:48 +0000613void SkMatrix44::mapMScalars(const SkMScalar src[4], SkMScalar dst[4]) const {
reed@google.com7d683352012-12-03 21:19:52 +0000614 SkMScalar storage[4];
615 SkMScalar* result = (src == dst) ? storage : dst;
skia.committer@gmail.com0264fb42012-12-06 02:01:25 +0000616
reed@google.com1ea95be2012-11-09 21:39:48 +0000617 for (int i = 0; i < 4; i++) {
618 SkMScalar value = 0;
619 for (int j = 0; j < 4; j++) {
620 value += fMat[j][i] * src[j];
621 }
reed@google.com7d683352012-12-03 21:19:52 +0000622 result[i] = value;
reed@google.com1ea95be2012-11-09 21:39:48 +0000623 }
skia.committer@gmail.com0264fb42012-12-06 02:01:25 +0000624
reed@google.com7d683352012-12-03 21:19:52 +0000625 if (storage == result) {
626 memcpy(dst, storage, sizeof(storage));
627 }
reed@google.com1ea95be2012-11-09 21:39:48 +0000628}
reed@google.com7d683352012-12-03 21:19:52 +0000629
reed@google.com1ea95be2012-11-09 21:39:48 +0000630#endif
631
reed@google.com99b5c7f2012-12-05 22:13:59 +0000632typedef void (*Map2Procf)(const SkMScalar mat[][4], const float src2[], int count, float dst4[]);
633typedef void (*Map2Procd)(const SkMScalar mat[][4], const double src2[], int count, double dst4[]);
634
635static void map2_if(const SkMScalar mat[][4], const float* SK_RESTRICT src2,
636 int count, float* SK_RESTRICT dst4) {
637 for (int i = 0; i < count; ++i) {
638 dst4[0] = src2[0];
639 dst4[1] = src2[1];
640 dst4[2] = 0;
641 dst4[3] = 1;
642 src2 += 2;
643 dst4 += 4;
644 }
645}
646
647static void map2_id(const SkMScalar mat[][4], const double* SK_RESTRICT src2,
648 int count, double* SK_RESTRICT dst4) {
649 for (int i = 0; i < count; ++i) {
650 dst4[0] = src2[0];
651 dst4[1] = src2[1];
652 dst4[2] = 0;
653 dst4[3] = 1;
654 src2 += 2;
655 dst4 += 4;
656 }
657}
658
659static void map2_tf(const SkMScalar mat[][4], const float* SK_RESTRICT src2,
660 int count, float* SK_RESTRICT dst4) {
661 const float mat30 = SkMScalarToFloat(mat[3][0]);
662 const float mat31 = SkMScalarToFloat(mat[3][1]);
663 const float mat32 = SkMScalarToFloat(mat[3][2]);
664 for (int n = 0; n < count; ++n) {
665 dst4[0] = src2[0] + mat30;
666 dst4[1] = src2[1] + mat31;
667 dst4[2] = mat32;
668 dst4[3] = 1;
669 src2 += 2;
670 dst4 += 4;
671 }
672}
673
674static void map2_td(const SkMScalar mat[][4], const double* SK_RESTRICT src2,
675 int count, double* SK_RESTRICT dst4) {
676 for (int n = 0; n < count; ++n) {
677 dst4[0] = src2[0] + mat[3][0];
678 dst4[1] = src2[1] + mat[3][1];
679 dst4[2] = mat[3][2];
680 dst4[3] = 1;
681 src2 += 2;
682 dst4 += 4;
683 }
684}
685
686static void map2_sf(const SkMScalar mat[][4], const float* SK_RESTRICT src2,
687 int count, float* SK_RESTRICT dst4) {
688 const float mat32 = SkMScalarToFloat(mat[3][2]);
689 for (int n = 0; n < count; ++n) {
690 dst4[0] = SkMScalarToFloat(mat[0][0] * src2[0] + mat[3][0]);
691 dst4[1] = SkMScalarToFloat(mat[1][1] * src2[1] + mat[3][1]);
692 dst4[2] = mat32;
693 dst4[3] = 1;
694 src2 += 2;
695 dst4 += 4;
696 }
697}
698
699static void map2_sd(const SkMScalar mat[][4], const double* SK_RESTRICT src2,
700 int count, double* SK_RESTRICT dst4) {
701 for (int n = 0; n < count; ++n) {
702 dst4[0] = mat[0][0] * src2[0] + mat[3][0];
703 dst4[1] = mat[1][1] * src2[1] + mat[3][1];
704 dst4[2] = mat[3][2];
705 dst4[3] = 1;
706 src2 += 2;
707 dst4 += 4;
708 }
709}
710
711static void map2_af(const SkMScalar mat[][4], const float* SK_RESTRICT src2,
712 int count, float* SK_RESTRICT dst4) {
713 double r;
714 for (int n = 0; n < count; ++n) {
715 double sx = src2[0];
716 double sy = src2[1];
717 r = mat[0][0] * sx + mat[1][0] * sy + mat[3][0];
718 dst4[0] = SkMScalarToFloat(r);
719 r = mat[0][1] * sx + mat[1][1] * sy + mat[3][1];
720 dst4[1] = SkMScalarToFloat(r);
721 r = mat[0][2] * sx + mat[1][2] * sy + mat[3][2];
722 dst4[2] = SkMScalarToFloat(r);
723 dst4[3] = 1;
724 src2 += 2;
725 dst4 += 4;
726 }
727}
728
729static void map2_ad(const SkMScalar mat[][4], const double* SK_RESTRICT src2,
730 int count, double* SK_RESTRICT dst4) {
731 for (int n = 0; n < count; ++n) {
732 double sx = src2[0];
733 double sy = src2[1];
734 dst4[0] = mat[0][0] * sx + mat[1][0] * sy + mat[3][0];
735 dst4[1] = mat[0][1] * sx + mat[1][1] * sy + mat[3][1];
736 dst4[2] = mat[0][2] * sx + mat[1][2] * sy + mat[3][2];
737 dst4[3] = 1;
738 src2 += 2;
739 dst4 += 4;
740 }
741}
742
743static void map2_pf(const SkMScalar mat[][4], const float* SK_RESTRICT src2,
744 int count, float* SK_RESTRICT dst4) {
745 double r;
746 for (int n = 0; n < count; ++n) {
747 double sx = src2[0];
748 double sy = src2[1];
749 for (int i = 0; i < 4; i++) {
750 r = mat[0][i] * sx + mat[1][i] * sy + mat[3][i];
751 dst4[i] = SkMScalarToFloat(r);
752 }
753 src2 += 2;
754 dst4 += 4;
755 }
756}
757
758static void map2_pd(const SkMScalar mat[][4], const double* SK_RESTRICT src2,
759 int count, double* SK_RESTRICT dst4) {
760 for (int n = 0; n < count; ++n) {
761 double sx = src2[0];
762 double sy = src2[1];
763 for (int i = 0; i < 4; i++) {
764 dst4[i] = mat[0][i] * sx + mat[1][i] * sy + mat[3][i];
765 }
766 src2 += 2;
767 dst4 += 4;
768 }
769}
770
771void SkMatrix44::map2(const float src2[], int count, float dst4[]) const {
772 static const Map2Procf gProc[] = {
773 map2_if, map2_tf, map2_sf, map2_sf, map2_af, map2_af, map2_af, map2_af
774 };
775
776 TypeMask mask = this->getType();
777 Map2Procf proc = (mask & kPerspective_Mask) ? map2_pf : gProc[mask];
778 proc(fMat, src2, count, dst4);
779}
780
781void SkMatrix44::map2(const double src2[], int count, double dst4[]) const {
782 static const Map2Procd gProc[] = {
783 map2_id, map2_td, map2_sd, map2_sd, map2_ad, map2_ad, map2_ad, map2_ad
784 };
skia.committer@gmail.com0264fb42012-12-06 02:01:25 +0000785
reed@google.com99b5c7f2012-12-05 22:13:59 +0000786 TypeMask mask = this->getType();
787 Map2Procd proc = (mask & kPerspective_Mask) ? map2_pd : gProc[mask];
788 proc(fMat, src2, count, dst4);
789}
790
reed@google.com8260a892011-06-13 14:02:52 +0000791///////////////////////////////////////////////////////////////////////////////
792
793void SkMatrix44::dump() const {
tomhudson@google.com9ac4a892011-06-28 13:53:13 +0000794 static const char* format =
795 "[%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 +0000796#if 0
tomhudson@google.com9ac4a892011-06-28 13:53:13 +0000797 SkDebugf(format,
reed@google.com8260a892011-06-13 14:02:52 +0000798 fMat[0][0], fMat[1][0], fMat[2][0], fMat[3][0],
799 fMat[0][1], fMat[1][1], fMat[2][1], fMat[3][1],
800 fMat[0][2], fMat[1][2], fMat[2][2], fMat[3][2],
801 fMat[0][3], fMat[1][3], fMat[2][3], fMat[3][3]);
tomhudson@google.com9ac4a892011-06-28 13:53:13 +0000802#else
803 SkDebugf(format,
804 fMat[0][0], fMat[0][1], fMat[0][2], fMat[0][3],
805 fMat[1][0], fMat[1][1], fMat[1][2], fMat[1][3],
806 fMat[2][0], fMat[2][1], fMat[2][2], fMat[2][3],
807 fMat[3][0], fMat[3][1], fMat[3][2], fMat[3][3]);
reed@google.com8260a892011-06-13 14:02:52 +0000808#endif
809}
810
811///////////////////////////////////////////////////////////////////////////////
812
reed@google.com7d683352012-12-03 21:19:52 +0000813// TODO: make this support src' perspective elements
814//
reed@google.com8260a892011-06-13 14:02:52 +0000815static void initFromMatrix(SkMScalar dst[4][4], const SkMatrix& src) {
816 sk_bzero(dst, 16 * sizeof(SkMScalar));
bsalomon@google.com72e49b82011-10-27 21:47:03 +0000817 dst[0][0] = SkScalarToMScalar(src[SkMatrix::kMScaleX]);
818 dst[1][0] = SkScalarToMScalar(src[SkMatrix::kMSkewX]);
819 dst[3][0] = SkScalarToMScalar(src[SkMatrix::kMTransX]);
820 dst[0][1] = SkScalarToMScalar(src[SkMatrix::kMSkewY]);
821 dst[1][1] = SkScalarToMScalar(src[SkMatrix::kMScaleY]);
822 dst[3][1] = SkScalarToMScalar(src[SkMatrix::kMTransY]);
reed@google.com8260a892011-06-13 14:02:52 +0000823 dst[2][2] = dst[3][3] = 1;
824}
825
826SkMatrix44::SkMatrix44(const SkMatrix& src) {
827 initFromMatrix(fMat, src);
828}
829
830SkMatrix44& SkMatrix44::operator=(const SkMatrix& src) {
831 initFromMatrix(fMat, src);
reed@google.com7d683352012-12-03 21:19:52 +0000832
833 if (src.isIdentity()) {
834 this->setTypeMask(kIdentity_Mask);
835 } else {
836 this->dirtyTypeMask();
837 }
reed@google.com8260a892011-06-13 14:02:52 +0000838 return *this;
839}
840
reed@google.com7d683352012-12-03 21:19:52 +0000841// TODO: make this support our perspective elements
842//
reed@google.com8260a892011-06-13 14:02:52 +0000843SkMatrix44::operator SkMatrix() const {
844 SkMatrix dst;
845 dst.reset(); // setup our perspective correctly for identity
846
bsalomon@google.com72e49b82011-10-27 21:47:03 +0000847 dst[SkMatrix::kMScaleX] = SkMScalarToScalar(fMat[0][0]);
848 dst[SkMatrix::kMSkewX] = SkMScalarToScalar(fMat[1][0]);
849 dst[SkMatrix::kMTransX] = SkMScalarToScalar(fMat[3][0]);
reed@google.com8260a892011-06-13 14:02:52 +0000850
bsalomon@google.com72e49b82011-10-27 21:47:03 +0000851 dst[SkMatrix::kMSkewY] = SkMScalarToScalar(fMat[0][1]);
852 dst[SkMatrix::kMScaleY] = SkMScalarToScalar(fMat[1][1]);
853 dst[SkMatrix::kMTransY] = SkMScalarToScalar(fMat[3][1]);
reed@google.com8260a892011-06-13 14:02:52 +0000854
855 return dst;
856}