blob: fbbefa07d7208517beef4e9b54fe339d811461a2 [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;
reed@google.com99b5c7f2012-12-05 22:13:59 +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() {
189 static SkMatrix44 gIdentity;
190 return gIdentity;
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 }
reed@google.com99b5c7f2012-12-05 22:13:59 +0000217
218 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 }
279
reed@google.com8260a892011-06-13 14:02:52 +0000280 SkMatrix44 tmp;
281 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 }
289
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 {
414 return fMat[0][0] * det3x3(fMat[1][1], fMat[1][2], fMat[1][3],
415 fMat[2][1], fMat[2][2], fMat[2][3],
416 fMat[3][1], fMat[3][2], fMat[3][3]) -
417 fMat[1][0] * det3x3(fMat[0][1], fMat[0][2], fMat[0][3],
418 fMat[2][1], fMat[2][2], fMat[2][3],
419 fMat[3][1], fMat[3][2], fMat[3][3]) +
420 fMat[2][0] * det3x3(fMat[0][1], fMat[0][2], fMat[0][3],
421 fMat[1][1], fMat[1][2], fMat[1][3],
422 fMat[3][1], fMat[3][2], fMat[3][3]) -
423 fMat[3][0] * det3x3(fMat[0][1], fMat[0][2], fMat[0][3],
424 fMat[1][1], fMat[1][2], fMat[1][3],
425 fMat[2][1], fMat[2][2], fMat[2][3]);
426}
427
428///////////////////////////////////////////////////////////////////////////////
429
430// just picked a small value. not sure how to pick the "right" one
431#define TOO_SMALL_FOR_DETERMINANT (1.e-8)
432
433static inline double dabs(double x) {
434 if (x < 0) {
435 x = -x;
436 }
437 return x;
438}
439
440bool SkMatrix44::invert(SkMatrix44* inverse) const {
reed@google.com99b5c7f2012-12-05 22:13:59 +0000441 const SkMatrix44::TypeMask mask = this->getType();
442
443 if (kIdentity_Mask == mask) {
reed@google.com7d683352012-12-03 21:19:52 +0000444 if (inverse) {
445 *inverse = *this;
446 return true;
447 }
448 }
449
reed@google.com99b5c7f2012-12-05 22:13:59 +0000450 if (kTranslate_Mask == mask) {
451 if (inverse) {
452 inverse->setTranslate(-fMat[3][0], -fMat[3][1], -fMat[3][2]);
453 }
454 return true;
455 }
456
457 if (bits_isonly(mask, kScale_Mask | kTranslate_Mask)) {
458 if (0 == fMat[0][0] * fMat[1][1] * fMat[2][2]) {
459 return false;
460 }
461 if (inverse) {
462 sk_bzero(inverse->fMat, sizeof(inverse->fMat));
463
464 inverse->fMat[3][0] = -fMat[3][0] / fMat[0][0];
465 inverse->fMat[3][1] = -fMat[3][1] / fMat[1][1];
466 inverse->fMat[3][2] = -fMat[3][2] / fMat[2][2];
467
468 inverse->fMat[0][0] = 1 / fMat[0][0];
469 inverse->fMat[1][1] = 1 / fMat[1][1];
470 inverse->fMat[2][2] = 1 / fMat[2][2];
471 inverse->fMat[3][3] = 1;
472
473 inverse->setTypeMask(mask);
474 }
475 return true;
476 }
477
reed@google.com8260a892011-06-13 14:02:52 +0000478 double det = this->determinant();
479 if (dabs(det) < TOO_SMALL_FOR_DETERMINANT) {
480 return false;
481 }
reed@google.com7d683352012-12-03 21:19:52 +0000482
483 // We now we will succeed, so return early if the caller doesn't actually
484 // want the computed inverse.
reed@google.com8260a892011-06-13 14:02:52 +0000485 if (NULL == inverse) {
486 return true;
487 }
488
489 // we explicitly promote to doubles to keep the intermediate values in
490 // higher precision (assuming SkMScalar isn't already a double)
491 double m00 = fMat[0][0];
492 double m01 = fMat[0][1];
493 double m02 = fMat[0][2];
494 double m03 = fMat[0][3];
495 double m10 = fMat[1][0];
496 double m11 = fMat[1][1];
497 double m12 = fMat[1][2];
498 double m13 = fMat[1][3];
499 double m20 = fMat[2][0];
500 double m21 = fMat[2][1];
501 double m22 = fMat[2][2];
502 double m23 = fMat[2][3];
503 double m30 = fMat[3][0];
504 double m31 = fMat[3][1];
505 double m32 = fMat[3][2];
506 double m33 = fMat[3][3];
507
508 double tmp[4][4];
509
510 tmp[0][0] = m12*m23*m31 - m13*m22*m31 + m13*m21*m32 - m11*m23*m32 - m12*m21*m33 + m11*m22*m33;
511 tmp[0][1] = m03*m22*m31 - m02*m23*m31 - m03*m21*m32 + m01*m23*m32 + m02*m21*m33 - m01*m22*m33;
512 tmp[0][2] = m02*m13*m31 - m03*m12*m31 + m03*m11*m32 - m01*m13*m32 - m02*m11*m33 + m01*m12*m33;
513 tmp[0][3] = m03*m12*m21 - m02*m13*m21 - m03*m11*m22 + m01*m13*m22 + m02*m11*m23 - m01*m12*m23;
514 tmp[1][0] = m13*m22*m30 - m12*m23*m30 - m13*m20*m32 + m10*m23*m32 + m12*m20*m33 - m10*m22*m33;
515 tmp[1][1] = m02*m23*m30 - m03*m22*m30 + m03*m20*m32 - m00*m23*m32 - m02*m20*m33 + m00*m22*m33;
516 tmp[1][2] = m03*m12*m30 - m02*m13*m30 - m03*m10*m32 + m00*m13*m32 + m02*m10*m33 - m00*m12*m33;
517 tmp[1][3] = m02*m13*m20 - m03*m12*m20 + m03*m10*m22 - m00*m13*m22 - m02*m10*m23 + m00*m12*m23;
518 tmp[2][0] = m11*m23*m30 - m13*m21*m30 + m13*m20*m31 - m10*m23*m31 - m11*m20*m33 + m10*m21*m33;
519 tmp[2][1] = m03*m21*m30 - m01*m23*m30 - m03*m20*m31 + m00*m23*m31 + m01*m20*m33 - m00*m21*m33;
520 tmp[2][2] = m01*m13*m30 - m03*m11*m30 + m03*m10*m31 - m00*m13*m31 - m01*m10*m33 + m00*m11*m33;
521 tmp[2][3] = m03*m11*m20 - m01*m13*m20 - m03*m10*m21 + m00*m13*m21 + m01*m10*m23 - m00*m11*m23;
522 tmp[3][0] = m12*m21*m30 - m11*m22*m30 - m12*m20*m31 + m10*m22*m31 + m11*m20*m32 - m10*m21*m32;
523 tmp[3][1] = m01*m22*m30 - m02*m21*m30 + m02*m20*m31 - m00*m22*m31 - m01*m20*m32 + m00*m21*m32;
524 tmp[3][2] = m02*m11*m30 - m01*m12*m30 - m02*m10*m31 + m00*m12*m31 + m01*m10*m32 - m00*m11*m32;
525 tmp[3][3] = m01*m12*m20 - m02*m11*m20 + m02*m10*m21 - m00*m12*m21 - m01*m10*m22 + m00*m11*m22;
526
527 double invDet = 1.0 / det;
528 for (int i = 0; i < 4; i++) {
529 for (int j = 0; j < 4; j++) {
530 inverse->fMat[i][j] = SkDoubleToMScalar(tmp[i][j] * invDet);
531 }
532 }
reed@google.com7d683352012-12-03 21:19:52 +0000533 inverse->dirtyTypeMask();
reed@google.com8260a892011-06-13 14:02:52 +0000534 return true;
535}
536
537///////////////////////////////////////////////////////////////////////////////
538
vollick@chromium.org9b21c252012-11-14 21:33:55 +0000539void SkMatrix44::transpose() {
540 SkTSwap(fMat[0][1], fMat[1][0]);
541 SkTSwap(fMat[0][2], fMat[2][0]);
542 SkTSwap(fMat[0][3], fMat[3][0]);
543 SkTSwap(fMat[1][2], fMat[2][1]);
544 SkTSwap(fMat[1][3], fMat[3][1]);
545 SkTSwap(fMat[2][3], fMat[3][2]);
reed@google.com7d683352012-12-03 21:19:52 +0000546
547 if (!this->isTriviallyIdentity()) {
548 this->dirtyTypeMask();
549 }
vollick@chromium.org9b21c252012-11-14 21:33:55 +0000550}
551
552///////////////////////////////////////////////////////////////////////////////
553
reed@google.com1ea95be2012-11-09 21:39:48 +0000554void SkMatrix44::mapScalars(const SkScalar src[4], SkScalar dst[4]) const {
reed@google.com7d683352012-12-03 21:19:52 +0000555 SkScalar storage[4];
556 SkScalar* result = (src == dst) ? storage : dst;
557
reed@google.com8260a892011-06-13 14:02:52 +0000558 for (int i = 0; i < 4; i++) {
559 SkMScalar value = 0;
560 for (int j = 0; j < 4; j++) {
561 value += fMat[j][i] * src[j];
562 }
bsalomon@google.com72e49b82011-10-27 21:47:03 +0000563 result[i] = SkMScalarToScalar(value);
reed@google.com8260a892011-06-13 14:02:52 +0000564 }
reed@google.com99b5c7f2012-12-05 22:13:59 +0000565
reed@google.com7d683352012-12-03 21:19:52 +0000566 if (storage == result) {
567 memcpy(dst, storage, sizeof(storage));
568 }
reed@google.com8260a892011-06-13 14:02:52 +0000569}
570
reed@google.com1ea95be2012-11-09 21:39:48 +0000571#ifdef SK_MSCALAR_IS_DOUBLE
reed@google.com7d683352012-12-03 21:19:52 +0000572
reed@google.com1ea95be2012-11-09 21:39:48 +0000573void SkMatrix44::mapMScalars(const SkMScalar src[4], SkMScalar dst[4]) const {
reed@google.com7d683352012-12-03 21:19:52 +0000574 SkMScalar storage[4];
575 SkMScalar* result = (src == dst) ? storage : dst;
reed@google.com99b5c7f2012-12-05 22:13:59 +0000576
reed@google.com1ea95be2012-11-09 21:39:48 +0000577 for (int i = 0; i < 4; i++) {
578 SkMScalar value = 0;
579 for (int j = 0; j < 4; j++) {
580 value += fMat[j][i] * src[j];
581 }
reed@google.com7d683352012-12-03 21:19:52 +0000582 result[i] = value;
reed@google.com1ea95be2012-11-09 21:39:48 +0000583 }
reed@google.com99b5c7f2012-12-05 22:13:59 +0000584
reed@google.com7d683352012-12-03 21:19:52 +0000585 if (storage == result) {
586 memcpy(dst, storage, sizeof(storage));
587 }
reed@google.com1ea95be2012-11-09 21:39:48 +0000588}
reed@google.com7d683352012-12-03 21:19:52 +0000589
reed@google.com1ea95be2012-11-09 21:39:48 +0000590#endif
591
reed@google.com99b5c7f2012-12-05 22:13:59 +0000592typedef void (*Map2Procf)(const SkMScalar mat[][4], const float src2[], int count, float dst4[]);
593typedef void (*Map2Procd)(const SkMScalar mat[][4], const double src2[], int count, double dst4[]);
594
595static void map2_if(const SkMScalar mat[][4], const float* SK_RESTRICT src2,
596 int count, float* SK_RESTRICT dst4) {
597 for (int i = 0; i < count; ++i) {
598 dst4[0] = src2[0];
599 dst4[1] = src2[1];
600 dst4[2] = 0;
601 dst4[3] = 1;
602 src2 += 2;
603 dst4 += 4;
604 }
605}
606
607static void map2_id(const SkMScalar mat[][4], const double* SK_RESTRICT src2,
608 int count, double* SK_RESTRICT dst4) {
609 for (int i = 0; i < count; ++i) {
610 dst4[0] = src2[0];
611 dst4[1] = src2[1];
612 dst4[2] = 0;
613 dst4[3] = 1;
614 src2 += 2;
615 dst4 += 4;
616 }
617}
618
619static void map2_tf(const SkMScalar mat[][4], const float* SK_RESTRICT src2,
620 int count, float* SK_RESTRICT dst4) {
621 const float mat30 = SkMScalarToFloat(mat[3][0]);
622 const float mat31 = SkMScalarToFloat(mat[3][1]);
623 const float mat32 = SkMScalarToFloat(mat[3][2]);
624 for (int n = 0; n < count; ++n) {
625 dst4[0] = src2[0] + mat30;
626 dst4[1] = src2[1] + mat31;
627 dst4[2] = mat32;
628 dst4[3] = 1;
629 src2 += 2;
630 dst4 += 4;
631 }
632}
633
634static void map2_td(const SkMScalar mat[][4], const double* SK_RESTRICT src2,
635 int count, double* SK_RESTRICT dst4) {
636 for (int n = 0; n < count; ++n) {
637 dst4[0] = src2[0] + mat[3][0];
638 dst4[1] = src2[1] + mat[3][1];
639 dst4[2] = mat[3][2];
640 dst4[3] = 1;
641 src2 += 2;
642 dst4 += 4;
643 }
644}
645
646static void map2_sf(const SkMScalar mat[][4], const float* SK_RESTRICT src2,
647 int count, float* SK_RESTRICT dst4) {
648 const float mat32 = SkMScalarToFloat(mat[3][2]);
649 for (int n = 0; n < count; ++n) {
650 dst4[0] = SkMScalarToFloat(mat[0][0] * src2[0] + mat[3][0]);
651 dst4[1] = SkMScalarToFloat(mat[1][1] * src2[1] + mat[3][1]);
652 dst4[2] = mat32;
653 dst4[3] = 1;
654 src2 += 2;
655 dst4 += 4;
656 }
657}
658
659static void map2_sd(const SkMScalar mat[][4], const double* SK_RESTRICT src2,
660 int count, double* SK_RESTRICT dst4) {
661 for (int n = 0; n < count; ++n) {
662 dst4[0] = mat[0][0] * src2[0] + mat[3][0];
663 dst4[1] = mat[1][1] * src2[1] + mat[3][1];
664 dst4[2] = mat[3][2];
665 dst4[3] = 1;
666 src2 += 2;
667 dst4 += 4;
668 }
669}
670
671static void map2_af(const SkMScalar mat[][4], const float* SK_RESTRICT src2,
672 int count, float* SK_RESTRICT dst4) {
673 double r;
674 for (int n = 0; n < count; ++n) {
675 double sx = src2[0];
676 double sy = src2[1];
677 r = mat[0][0] * sx + mat[1][0] * sy + mat[3][0];
678 dst4[0] = SkMScalarToFloat(r);
679 r = mat[0][1] * sx + mat[1][1] * sy + mat[3][1];
680 dst4[1] = SkMScalarToFloat(r);
681 r = mat[0][2] * sx + mat[1][2] * sy + mat[3][2];
682 dst4[2] = SkMScalarToFloat(r);
683 dst4[3] = 1;
684 src2 += 2;
685 dst4 += 4;
686 }
687}
688
689static void map2_ad(const SkMScalar mat[][4], const double* SK_RESTRICT src2,
690 int count, double* SK_RESTRICT dst4) {
691 for (int n = 0; n < count; ++n) {
692 double sx = src2[0];
693 double sy = src2[1];
694 dst4[0] = mat[0][0] * sx + mat[1][0] * sy + mat[3][0];
695 dst4[1] = mat[0][1] * sx + mat[1][1] * sy + mat[3][1];
696 dst4[2] = mat[0][2] * sx + mat[1][2] * sy + mat[3][2];
697 dst4[3] = 1;
698 src2 += 2;
699 dst4 += 4;
700 }
701}
702
703static void map2_pf(const SkMScalar mat[][4], const float* SK_RESTRICT src2,
704 int count, float* SK_RESTRICT dst4) {
705 double r;
706 for (int n = 0; n < count; ++n) {
707 double sx = src2[0];
708 double sy = src2[1];
709 for (int i = 0; i < 4; i++) {
710 r = mat[0][i] * sx + mat[1][i] * sy + mat[3][i];
711 dst4[i] = SkMScalarToFloat(r);
712 }
713 src2 += 2;
714 dst4 += 4;
715 }
716}
717
718static void map2_pd(const SkMScalar mat[][4], const double* SK_RESTRICT src2,
719 int count, double* SK_RESTRICT dst4) {
720 for (int n = 0; n < count; ++n) {
721 double sx = src2[0];
722 double sy = src2[1];
723 for (int i = 0; i < 4; i++) {
724 dst4[i] = mat[0][i] * sx + mat[1][i] * sy + mat[3][i];
725 }
726 src2 += 2;
727 dst4 += 4;
728 }
729}
730
731void SkMatrix44::map2(const float src2[], int count, float dst4[]) const {
732 static const Map2Procf gProc[] = {
733 map2_if, map2_tf, map2_sf, map2_sf, map2_af, map2_af, map2_af, map2_af
734 };
735
736 TypeMask mask = this->getType();
737 Map2Procf proc = (mask & kPerspective_Mask) ? map2_pf : gProc[mask];
738 proc(fMat, src2, count, dst4);
739}
740
741void SkMatrix44::map2(const double src2[], int count, double dst4[]) const {
742 static const Map2Procd gProc[] = {
743 map2_id, map2_td, map2_sd, map2_sd, map2_ad, map2_ad, map2_ad, map2_ad
744 };
745
746 TypeMask mask = this->getType();
747 Map2Procd proc = (mask & kPerspective_Mask) ? map2_pd : gProc[mask];
748 proc(fMat, src2, count, dst4);
749}
750
reed@google.com8260a892011-06-13 14:02:52 +0000751///////////////////////////////////////////////////////////////////////////////
752
753void SkMatrix44::dump() const {
tomhudson@google.com9ac4a892011-06-28 13:53:13 +0000754 static const char* format =
755 "[%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 +0000756#if 0
tomhudson@google.com9ac4a892011-06-28 13:53:13 +0000757 SkDebugf(format,
reed@google.com8260a892011-06-13 14:02:52 +0000758 fMat[0][0], fMat[1][0], fMat[2][0], fMat[3][0],
759 fMat[0][1], fMat[1][1], fMat[2][1], fMat[3][1],
760 fMat[0][2], fMat[1][2], fMat[2][2], fMat[3][2],
761 fMat[0][3], fMat[1][3], fMat[2][3], fMat[3][3]);
tomhudson@google.com9ac4a892011-06-28 13:53:13 +0000762#else
763 SkDebugf(format,
764 fMat[0][0], fMat[0][1], fMat[0][2], fMat[0][3],
765 fMat[1][0], fMat[1][1], fMat[1][2], fMat[1][3],
766 fMat[2][0], fMat[2][1], fMat[2][2], fMat[2][3],
767 fMat[3][0], fMat[3][1], fMat[3][2], fMat[3][3]);
reed@google.com8260a892011-06-13 14:02:52 +0000768#endif
769}
770
771///////////////////////////////////////////////////////////////////////////////
772
reed@google.com7d683352012-12-03 21:19:52 +0000773// TODO: make this support src' perspective elements
774//
reed@google.com8260a892011-06-13 14:02:52 +0000775static void initFromMatrix(SkMScalar dst[4][4], const SkMatrix& src) {
776 sk_bzero(dst, 16 * sizeof(SkMScalar));
bsalomon@google.com72e49b82011-10-27 21:47:03 +0000777 dst[0][0] = SkScalarToMScalar(src[SkMatrix::kMScaleX]);
778 dst[1][0] = SkScalarToMScalar(src[SkMatrix::kMSkewX]);
779 dst[3][0] = SkScalarToMScalar(src[SkMatrix::kMTransX]);
780 dst[0][1] = SkScalarToMScalar(src[SkMatrix::kMSkewY]);
781 dst[1][1] = SkScalarToMScalar(src[SkMatrix::kMScaleY]);
782 dst[3][1] = SkScalarToMScalar(src[SkMatrix::kMTransY]);
reed@google.com8260a892011-06-13 14:02:52 +0000783 dst[2][2] = dst[3][3] = 1;
784}
785
786SkMatrix44::SkMatrix44(const SkMatrix& src) {
787 initFromMatrix(fMat, src);
788}
789
790SkMatrix44& SkMatrix44::operator=(const SkMatrix& src) {
791 initFromMatrix(fMat, src);
reed@google.com7d683352012-12-03 21:19:52 +0000792
793 if (src.isIdentity()) {
794 this->setTypeMask(kIdentity_Mask);
795 } else {
796 this->dirtyTypeMask();
797 }
reed@google.com8260a892011-06-13 14:02:52 +0000798 return *this;
799}
800
reed@google.com7d683352012-12-03 21:19:52 +0000801// TODO: make this support our perspective elements
802//
reed@google.com8260a892011-06-13 14:02:52 +0000803SkMatrix44::operator SkMatrix() const {
804 SkMatrix dst;
805 dst.reset(); // setup our perspective correctly for identity
806
bsalomon@google.com72e49b82011-10-27 21:47:03 +0000807 dst[SkMatrix::kMScaleX] = SkMScalarToScalar(fMat[0][0]);
808 dst[SkMatrix::kMSkewX] = SkMScalarToScalar(fMat[1][0]);
809 dst[SkMatrix::kMTransX] = SkMScalarToScalar(fMat[3][0]);
reed@google.com8260a892011-06-13 14:02:52 +0000810
bsalomon@google.com72e49b82011-10-27 21:47:03 +0000811 dst[SkMatrix::kMSkewY] = SkMScalarToScalar(fMat[0][1]);
812 dst[SkMatrix::kMScaleY] = SkMScalarToScalar(fMat[1][1]);
813 dst[SkMatrix::kMTransY] = SkMScalarToScalar(fMat[3][1]);
reed@google.com8260a892011-06-13 14:02:52 +0000814
815 return dst;
816}