blob: f76f405c074f2cd2739963f46ae1b9cd22a413db [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() {
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 }
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.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 }
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
reed@google.com8260a892011-06-13 14:02:52 +0000421 return fMat[0][0] * det3x3(fMat[1][1], fMat[1][2], fMat[1][3],
422 fMat[2][1], fMat[2][2], fMat[2][3],
423 fMat[3][1], fMat[3][2], fMat[3][3]) -
424 fMat[1][0] * det3x3(fMat[0][1], fMat[0][2], fMat[0][3],
425 fMat[2][1], fMat[2][2], fMat[2][3],
426 fMat[3][1], fMat[3][2], fMat[3][3]) +
427 fMat[2][0] * det3x3(fMat[0][1], fMat[0][2], fMat[0][3],
428 fMat[1][1], fMat[1][2], fMat[1][3],
429 fMat[3][1], fMat[3][2], fMat[3][3]) -
430 fMat[3][0] * det3x3(fMat[0][1], fMat[0][2], fMat[0][3],
431 fMat[1][1], fMat[1][2], fMat[1][3],
432 fMat[2][1], fMat[2][2], fMat[2][3]);
433}
434
435///////////////////////////////////////////////////////////////////////////////
436
437// just picked a small value. not sure how to pick the "right" one
438#define TOO_SMALL_FOR_DETERMINANT (1.e-8)
439
440static inline double dabs(double x) {
441 if (x < 0) {
442 x = -x;
443 }
444 return x;
445}
446
447bool SkMatrix44::invert(SkMatrix44* inverse) const {
mike@reedtribe.orgf8b1ebc2012-12-10 03:27:47 +0000448 if (this->isIdentity()) {
reed@google.com7d683352012-12-03 21:19:52 +0000449 if (inverse) {
450 *inverse = *this;
451 return true;
452 }
453 }
mike@reedtribe.orgf8b1ebc2012-12-10 03:27:47 +0000454 if (this->isTranslate()) {
reed@google.com99b5c7f2012-12-05 22:13:59 +0000455 if (inverse) {
456 inverse->setTranslate(-fMat[3][0], -fMat[3][1], -fMat[3][2]);
457 }
458 return true;
459 }
mike@reedtribe.orgf8b1ebc2012-12-10 03:27:47 +0000460 if (this->isScaleTranslate()) {
reed@google.com99b5c7f2012-12-05 22:13:59 +0000461 if (0 == fMat[0][0] * fMat[1][1] * fMat[2][2]) {
462 return false;
463 }
464 if (inverse) {
465 sk_bzero(inverse->fMat, sizeof(inverse->fMat));
466
467 inverse->fMat[3][0] = -fMat[3][0] / fMat[0][0];
468 inverse->fMat[3][1] = -fMat[3][1] / fMat[1][1];
469 inverse->fMat[3][2] = -fMat[3][2] / fMat[2][2];
470
471 inverse->fMat[0][0] = 1 / fMat[0][0];
472 inverse->fMat[1][1] = 1 / fMat[1][1];
473 inverse->fMat[2][2] = 1 / fMat[2][2];
474 inverse->fMat[3][3] = 1;
475
mike@reedtribe.orgf8b1ebc2012-12-10 03:27:47 +0000476 inverse->setTypeMask(this->getType());
reed@google.com99b5c7f2012-12-05 22:13:59 +0000477 }
478 return true;
479 }
480
reed@google.com8260a892011-06-13 14:02:52 +0000481 double det = this->determinant();
482 if (dabs(det) < TOO_SMALL_FOR_DETERMINANT) {
483 return false;
484 }
reed@google.com7d683352012-12-03 21:19:52 +0000485
486 // We now we will succeed, so return early if the caller doesn't actually
487 // want the computed inverse.
reed@google.com8260a892011-06-13 14:02:52 +0000488 if (NULL == inverse) {
489 return true;
490 }
491
492 // we explicitly promote to doubles to keep the intermediate values in
493 // higher precision (assuming SkMScalar isn't already a double)
494 double m00 = fMat[0][0];
495 double m01 = fMat[0][1];
496 double m02 = fMat[0][2];
497 double m03 = fMat[0][3];
498 double m10 = fMat[1][0];
499 double m11 = fMat[1][1];
500 double m12 = fMat[1][2];
501 double m13 = fMat[1][3];
502 double m20 = fMat[2][0];
503 double m21 = fMat[2][1];
504 double m22 = fMat[2][2];
505 double m23 = fMat[2][3];
506 double m30 = fMat[3][0];
507 double m31 = fMat[3][1];
508 double m32 = fMat[3][2];
509 double m33 = fMat[3][3];
510
511 double tmp[4][4];
512
513 tmp[0][0] = m12*m23*m31 - m13*m22*m31 + m13*m21*m32 - m11*m23*m32 - m12*m21*m33 + m11*m22*m33;
514 tmp[0][1] = m03*m22*m31 - m02*m23*m31 - m03*m21*m32 + m01*m23*m32 + m02*m21*m33 - m01*m22*m33;
515 tmp[0][2] = m02*m13*m31 - m03*m12*m31 + m03*m11*m32 - m01*m13*m32 - m02*m11*m33 + m01*m12*m33;
516 tmp[0][3] = m03*m12*m21 - m02*m13*m21 - m03*m11*m22 + m01*m13*m22 + m02*m11*m23 - m01*m12*m23;
517 tmp[1][0] = m13*m22*m30 - m12*m23*m30 - m13*m20*m32 + m10*m23*m32 + m12*m20*m33 - m10*m22*m33;
518 tmp[1][1] = m02*m23*m30 - m03*m22*m30 + m03*m20*m32 - m00*m23*m32 - m02*m20*m33 + m00*m22*m33;
519 tmp[1][2] = m03*m12*m30 - m02*m13*m30 - m03*m10*m32 + m00*m13*m32 + m02*m10*m33 - m00*m12*m33;
520 tmp[1][3] = m02*m13*m20 - m03*m12*m20 + m03*m10*m22 - m00*m13*m22 - m02*m10*m23 + m00*m12*m23;
521 tmp[2][0] = m11*m23*m30 - m13*m21*m30 + m13*m20*m31 - m10*m23*m31 - m11*m20*m33 + m10*m21*m33;
522 tmp[2][1] = m03*m21*m30 - m01*m23*m30 - m03*m20*m31 + m00*m23*m31 + m01*m20*m33 - m00*m21*m33;
523 tmp[2][2] = m01*m13*m30 - m03*m11*m30 + m03*m10*m31 - m00*m13*m31 - m01*m10*m33 + m00*m11*m33;
524 tmp[2][3] = m03*m11*m20 - m01*m13*m20 - m03*m10*m21 + m00*m13*m21 + m01*m10*m23 - m00*m11*m23;
525 tmp[3][0] = m12*m21*m30 - m11*m22*m30 - m12*m20*m31 + m10*m22*m31 + m11*m20*m32 - m10*m21*m32;
526 tmp[3][1] = m01*m22*m30 - m02*m21*m30 + m02*m20*m31 - m00*m22*m31 - m01*m20*m32 + m00*m21*m32;
527 tmp[3][2] = m02*m11*m30 - m01*m12*m30 - m02*m10*m31 + m00*m12*m31 + m01*m10*m32 - m00*m11*m32;
528 tmp[3][3] = m01*m12*m20 - m02*m11*m20 + m02*m10*m21 - m00*m12*m21 - m01*m10*m22 + m00*m11*m22;
529
530 double invDet = 1.0 / det;
531 for (int i = 0; i < 4; i++) {
532 for (int j = 0; j < 4; j++) {
533 inverse->fMat[i][j] = SkDoubleToMScalar(tmp[i][j] * invDet);
534 }
535 }
reed@google.com7d683352012-12-03 21:19:52 +0000536 inverse->dirtyTypeMask();
reed@google.com8260a892011-06-13 14:02:52 +0000537 return true;
538}
539
540///////////////////////////////////////////////////////////////////////////////
541
vollick@chromium.org9b21c252012-11-14 21:33:55 +0000542void SkMatrix44::transpose() {
543 SkTSwap(fMat[0][1], fMat[1][0]);
544 SkTSwap(fMat[0][2], fMat[2][0]);
545 SkTSwap(fMat[0][3], fMat[3][0]);
546 SkTSwap(fMat[1][2], fMat[2][1]);
547 SkTSwap(fMat[1][3], fMat[3][1]);
548 SkTSwap(fMat[2][3], fMat[3][2]);
reed@google.com7d683352012-12-03 21:19:52 +0000549
550 if (!this->isTriviallyIdentity()) {
551 this->dirtyTypeMask();
552 }
vollick@chromium.org9b21c252012-11-14 21:33:55 +0000553}
554
555///////////////////////////////////////////////////////////////////////////////
556
reed@google.com1ea95be2012-11-09 21:39:48 +0000557void SkMatrix44::mapScalars(const SkScalar src[4], SkScalar dst[4]) const {
reed@google.com7d683352012-12-03 21:19:52 +0000558 SkScalar storage[4];
559 SkScalar* result = (src == dst) ? storage : dst;
560
reed@google.com8260a892011-06-13 14:02:52 +0000561 for (int i = 0; i < 4; i++) {
562 SkMScalar value = 0;
563 for (int j = 0; j < 4; j++) {
564 value += fMat[j][i] * src[j];
565 }
bsalomon@google.com72e49b82011-10-27 21:47:03 +0000566 result[i] = SkMScalarToScalar(value);
reed@google.com8260a892011-06-13 14:02:52 +0000567 }
skia.committer@gmail.com0264fb42012-12-06 02:01:25 +0000568
reed@google.com7d683352012-12-03 21:19:52 +0000569 if (storage == result) {
570 memcpy(dst, storage, sizeof(storage));
571 }
reed@google.com8260a892011-06-13 14:02:52 +0000572}
573
reed@google.com1ea95be2012-11-09 21:39:48 +0000574#ifdef SK_MSCALAR_IS_DOUBLE
reed@google.com7d683352012-12-03 21:19:52 +0000575
reed@google.com1ea95be2012-11-09 21:39:48 +0000576void SkMatrix44::mapMScalars(const SkMScalar src[4], SkMScalar dst[4]) const {
reed@google.com7d683352012-12-03 21:19:52 +0000577 SkMScalar storage[4];
578 SkMScalar* result = (src == dst) ? storage : dst;
skia.committer@gmail.com0264fb42012-12-06 02:01:25 +0000579
reed@google.com1ea95be2012-11-09 21:39:48 +0000580 for (int i = 0; i < 4; i++) {
581 SkMScalar value = 0;
582 for (int j = 0; j < 4; j++) {
583 value += fMat[j][i] * src[j];
584 }
reed@google.com7d683352012-12-03 21:19:52 +0000585 result[i] = value;
reed@google.com1ea95be2012-11-09 21:39:48 +0000586 }
skia.committer@gmail.com0264fb42012-12-06 02:01:25 +0000587
reed@google.com7d683352012-12-03 21:19:52 +0000588 if (storage == result) {
589 memcpy(dst, storage, sizeof(storage));
590 }
reed@google.com1ea95be2012-11-09 21:39:48 +0000591}
reed@google.com7d683352012-12-03 21:19:52 +0000592
reed@google.com1ea95be2012-11-09 21:39:48 +0000593#endif
594
reed@google.com99b5c7f2012-12-05 22:13:59 +0000595typedef void (*Map2Procf)(const SkMScalar mat[][4], const float src2[], int count, float dst4[]);
596typedef void (*Map2Procd)(const SkMScalar mat[][4], const double src2[], int count, double dst4[]);
597
598static void map2_if(const SkMScalar mat[][4], const float* SK_RESTRICT src2,
599 int count, float* SK_RESTRICT dst4) {
600 for (int i = 0; i < count; ++i) {
601 dst4[0] = src2[0];
602 dst4[1] = src2[1];
603 dst4[2] = 0;
604 dst4[3] = 1;
605 src2 += 2;
606 dst4 += 4;
607 }
608}
609
610static void map2_id(const SkMScalar mat[][4], const double* SK_RESTRICT src2,
611 int count, double* SK_RESTRICT dst4) {
612 for (int i = 0; i < count; ++i) {
613 dst4[0] = src2[0];
614 dst4[1] = src2[1];
615 dst4[2] = 0;
616 dst4[3] = 1;
617 src2 += 2;
618 dst4 += 4;
619 }
620}
621
622static void map2_tf(const SkMScalar mat[][4], const float* SK_RESTRICT src2,
623 int count, float* SK_RESTRICT dst4) {
624 const float mat30 = SkMScalarToFloat(mat[3][0]);
625 const float mat31 = SkMScalarToFloat(mat[3][1]);
626 const float mat32 = SkMScalarToFloat(mat[3][2]);
627 for (int n = 0; n < count; ++n) {
628 dst4[0] = src2[0] + mat30;
629 dst4[1] = src2[1] + mat31;
630 dst4[2] = mat32;
631 dst4[3] = 1;
632 src2 += 2;
633 dst4 += 4;
634 }
635}
636
637static void map2_td(const SkMScalar mat[][4], const double* SK_RESTRICT src2,
638 int count, double* SK_RESTRICT dst4) {
639 for (int n = 0; n < count; ++n) {
640 dst4[0] = src2[0] + mat[3][0];
641 dst4[1] = src2[1] + mat[3][1];
642 dst4[2] = mat[3][2];
643 dst4[3] = 1;
644 src2 += 2;
645 dst4 += 4;
646 }
647}
648
649static void map2_sf(const SkMScalar mat[][4], const float* SK_RESTRICT src2,
650 int count, float* SK_RESTRICT dst4) {
651 const float mat32 = SkMScalarToFloat(mat[3][2]);
652 for (int n = 0; n < count; ++n) {
653 dst4[0] = SkMScalarToFloat(mat[0][0] * src2[0] + mat[3][0]);
654 dst4[1] = SkMScalarToFloat(mat[1][1] * src2[1] + mat[3][1]);
655 dst4[2] = mat32;
656 dst4[3] = 1;
657 src2 += 2;
658 dst4 += 4;
659 }
660}
661
662static void map2_sd(const SkMScalar mat[][4], const double* SK_RESTRICT src2,
663 int count, double* SK_RESTRICT dst4) {
664 for (int n = 0; n < count; ++n) {
665 dst4[0] = mat[0][0] * src2[0] + mat[3][0];
666 dst4[1] = mat[1][1] * src2[1] + mat[3][1];
667 dst4[2] = mat[3][2];
668 dst4[3] = 1;
669 src2 += 2;
670 dst4 += 4;
671 }
672}
673
674static void map2_af(const SkMScalar mat[][4], const float* SK_RESTRICT src2,
675 int count, float* SK_RESTRICT dst4) {
676 double r;
677 for (int n = 0; n < count; ++n) {
678 double sx = src2[0];
679 double sy = src2[1];
680 r = mat[0][0] * sx + mat[1][0] * sy + mat[3][0];
681 dst4[0] = SkMScalarToFloat(r);
682 r = mat[0][1] * sx + mat[1][1] * sy + mat[3][1];
683 dst4[1] = SkMScalarToFloat(r);
684 r = mat[0][2] * sx + mat[1][2] * sy + mat[3][2];
685 dst4[2] = SkMScalarToFloat(r);
686 dst4[3] = 1;
687 src2 += 2;
688 dst4 += 4;
689 }
690}
691
692static void map2_ad(const SkMScalar mat[][4], const double* SK_RESTRICT src2,
693 int count, double* SK_RESTRICT dst4) {
694 for (int n = 0; n < count; ++n) {
695 double sx = src2[0];
696 double sy = src2[1];
697 dst4[0] = mat[0][0] * sx + mat[1][0] * sy + mat[3][0];
698 dst4[1] = mat[0][1] * sx + mat[1][1] * sy + mat[3][1];
699 dst4[2] = mat[0][2] * sx + mat[1][2] * sy + mat[3][2];
700 dst4[3] = 1;
701 src2 += 2;
702 dst4 += 4;
703 }
704}
705
706static void map2_pf(const SkMScalar mat[][4], const float* SK_RESTRICT src2,
707 int count, float* SK_RESTRICT dst4) {
708 double r;
709 for (int n = 0; n < count; ++n) {
710 double sx = src2[0];
711 double sy = src2[1];
712 for (int i = 0; i < 4; i++) {
713 r = mat[0][i] * sx + mat[1][i] * sy + mat[3][i];
714 dst4[i] = SkMScalarToFloat(r);
715 }
716 src2 += 2;
717 dst4 += 4;
718 }
719}
720
721static void map2_pd(const SkMScalar mat[][4], const double* SK_RESTRICT src2,
722 int count, double* SK_RESTRICT dst4) {
723 for (int n = 0; n < count; ++n) {
724 double sx = src2[0];
725 double sy = src2[1];
726 for (int i = 0; i < 4; i++) {
727 dst4[i] = mat[0][i] * sx + mat[1][i] * sy + mat[3][i];
728 }
729 src2 += 2;
730 dst4 += 4;
731 }
732}
733
734void SkMatrix44::map2(const float src2[], int count, float dst4[]) const {
735 static const Map2Procf gProc[] = {
736 map2_if, map2_tf, map2_sf, map2_sf, map2_af, map2_af, map2_af, map2_af
737 };
738
739 TypeMask mask = this->getType();
740 Map2Procf proc = (mask & kPerspective_Mask) ? map2_pf : gProc[mask];
741 proc(fMat, src2, count, dst4);
742}
743
744void SkMatrix44::map2(const double src2[], int count, double dst4[]) const {
745 static const Map2Procd gProc[] = {
746 map2_id, map2_td, map2_sd, map2_sd, map2_ad, map2_ad, map2_ad, map2_ad
747 };
skia.committer@gmail.com0264fb42012-12-06 02:01:25 +0000748
reed@google.com99b5c7f2012-12-05 22:13:59 +0000749 TypeMask mask = this->getType();
750 Map2Procd proc = (mask & kPerspective_Mask) ? map2_pd : gProc[mask];
751 proc(fMat, src2, count, dst4);
752}
753
reed@google.com8260a892011-06-13 14:02:52 +0000754///////////////////////////////////////////////////////////////////////////////
755
756void SkMatrix44::dump() const {
tomhudson@google.com9ac4a892011-06-28 13:53:13 +0000757 static const char* format =
758 "[%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 +0000759#if 0
tomhudson@google.com9ac4a892011-06-28 13:53:13 +0000760 SkDebugf(format,
reed@google.com8260a892011-06-13 14:02:52 +0000761 fMat[0][0], fMat[1][0], fMat[2][0], fMat[3][0],
762 fMat[0][1], fMat[1][1], fMat[2][1], fMat[3][1],
763 fMat[0][2], fMat[1][2], fMat[2][2], fMat[3][2],
764 fMat[0][3], fMat[1][3], fMat[2][3], fMat[3][3]);
tomhudson@google.com9ac4a892011-06-28 13:53:13 +0000765#else
766 SkDebugf(format,
767 fMat[0][0], fMat[0][1], fMat[0][2], fMat[0][3],
768 fMat[1][0], fMat[1][1], fMat[1][2], fMat[1][3],
769 fMat[2][0], fMat[2][1], fMat[2][2], fMat[2][3],
770 fMat[3][0], fMat[3][1], fMat[3][2], fMat[3][3]);
reed@google.com8260a892011-06-13 14:02:52 +0000771#endif
772}
773
774///////////////////////////////////////////////////////////////////////////////
775
reed@google.com7d683352012-12-03 21:19:52 +0000776// TODO: make this support src' perspective elements
777//
reed@google.com8260a892011-06-13 14:02:52 +0000778static void initFromMatrix(SkMScalar dst[4][4], const SkMatrix& src) {
779 sk_bzero(dst, 16 * sizeof(SkMScalar));
bsalomon@google.com72e49b82011-10-27 21:47:03 +0000780 dst[0][0] = SkScalarToMScalar(src[SkMatrix::kMScaleX]);
781 dst[1][0] = SkScalarToMScalar(src[SkMatrix::kMSkewX]);
782 dst[3][0] = SkScalarToMScalar(src[SkMatrix::kMTransX]);
783 dst[0][1] = SkScalarToMScalar(src[SkMatrix::kMSkewY]);
784 dst[1][1] = SkScalarToMScalar(src[SkMatrix::kMScaleY]);
785 dst[3][1] = SkScalarToMScalar(src[SkMatrix::kMTransY]);
reed@google.com8260a892011-06-13 14:02:52 +0000786 dst[2][2] = dst[3][3] = 1;
787}
788
789SkMatrix44::SkMatrix44(const SkMatrix& src) {
790 initFromMatrix(fMat, src);
791}
792
793SkMatrix44& SkMatrix44::operator=(const SkMatrix& src) {
794 initFromMatrix(fMat, src);
reed@google.com7d683352012-12-03 21:19:52 +0000795
796 if (src.isIdentity()) {
797 this->setTypeMask(kIdentity_Mask);
798 } else {
799 this->dirtyTypeMask();
800 }
reed@google.com8260a892011-06-13 14:02:52 +0000801 return *this;
802}
803
reed@google.com7d683352012-12-03 21:19:52 +0000804// TODO: make this support our perspective elements
805//
reed@google.com8260a892011-06-13 14:02:52 +0000806SkMatrix44::operator SkMatrix() const {
807 SkMatrix dst;
808 dst.reset(); // setup our perspective correctly for identity
809
bsalomon@google.com72e49b82011-10-27 21:47:03 +0000810 dst[SkMatrix::kMScaleX] = SkMScalarToScalar(fMat[0][0]);
811 dst[SkMatrix::kMSkewX] = SkMScalarToScalar(fMat[1][0]);
812 dst[SkMatrix::kMTransX] = SkMScalarToScalar(fMat[3][0]);
reed@google.com8260a892011-06-13 14:02:52 +0000813
bsalomon@google.com72e49b82011-10-27 21:47:03 +0000814 dst[SkMatrix::kMSkewY] = SkMScalarToScalar(fMat[0][1]);
815 dst[SkMatrix::kMScaleY] = SkMScalarToScalar(fMat[1][1]);
816 dst[SkMatrix::kMTransY] = SkMScalarToScalar(fMat[3][1]);
reed@google.com8260a892011-06-13 14:02:52 +0000817
818 return dst;
819}