blob: 658d5c1aa845915a0418371ba7851b66fced6657 [file] [log] [blame]
reed@google.com8260a892011-06-13 14:02:52 +00001/*
epoger@google.comec3ed6a2011-07-28 14:26:00 +00002 * Copyright 2011 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
reed@google.com8260a892011-06-13 14:02:52 +00006 */
7
reed@google.com8260a892011-06-13 14:02:52 +00008#include "SkMatrix44.h"
9
reed@google.com7d683352012-12-03 21:19:52 +000010static inline bool eq4(const SkMScalar* SK_RESTRICT a,
11 const SkMScalar* SK_RESTRICT b) {
12 return (a[0] == b[0]) & (a[1] == b[1]) & (a[2] == b[2]) & (a[3] == b[3]);
13}
jamesr@chromium.orgdeb4c162012-11-29 21:17:16 +000014
reed@google.com7d683352012-12-03 21:19:52 +000015bool SkMatrix44::operator==(const SkMatrix44& other) const {
16 if (this == &other) {
17 return true;
18 }
19
20 if (this->isTriviallyIdentity() && other.isTriviallyIdentity()) {
21 return true;
22 }
23
24 const SkMScalar* SK_RESTRICT a = &fMat[0][0];
25 const SkMScalar* SK_RESTRICT b = &other.fMat[0][0];
26
27#if 0
reed@google.com631940c2012-11-27 13:13:22 +000028 for (int i = 0; i < 16; ++i) {
29 if (a[i] != b[i]) {
30 return false;
31 }
32 }
33 return true;
reed@google.com7d683352012-12-03 21:19:52 +000034#else
35 // to reduce branch instructions, we compare 4 at a time.
36 // see bench/Matrix44Bench.cpp for test.
37 if (!eq4(&a[0], &b[0])) {
38 return false;
39 }
40 if (!eq4(&a[4], &b[4])) {
41 return false;
42 }
43 if (!eq4(&a[8], &b[8])) {
44 return false;
45 }
46 return eq4(&a[12], &b[12]);
47#endif
48}
49
50///////////////////////////////////////////////////////////////////////////////
51
52int SkMatrix44::computeTypeMask() const {
53 unsigned mask = 0;
skia.committer@gmail.com0264fb42012-12-06 02:01:25 +000054
reed@google.com7d683352012-12-03 21:19:52 +000055 if (0 != perspX() || 0 != perspY() || 0 != perspZ() || 1 != fMat[3][3]) {
56 return kTranslate_Mask | kScale_Mask | kAffine_Mask | kPerspective_Mask;
57 }
58
59 if (0 != transX() || 0 != transY() || 0 != transZ()) {
60 mask |= kTranslate_Mask;
61 }
62
63 if (1 != scaleX() || 1 != scaleY() || 1 != scaleZ()) {
64 mask |= kScale_Mask;
65 }
66
67 if (0 != fMat[1][0] || 0 != fMat[0][1] || 0 != fMat[0][2] ||
68 0 != fMat[2][0] || 0 != fMat[1][2] || 0 != fMat[2][1]) {
69 mask |= kAffine_Mask;
70 }
71
72 return mask;
reed@google.com8260a892011-06-13 14:02:52 +000073}
74
75///////////////////////////////////////////////////////////////////////////////
76
reed@google.comda9fac02011-06-13 14:46:52 +000077void SkMatrix44::asColMajorf(float dst[]) const {
78 const SkMScalar* src = &fMat[0][0];
79#ifdef SK_MSCALAR_IS_DOUBLE
80 for (int i = 0; i < 16; ++i) {
81 dst[i] = SkMScalarToFloat(src[i]);
82 }
vollick@chromium.org5596a692012-11-13 20:12:00 +000083#elif defined SK_MSCALAR_IS_FLOAT
reed@google.comda9fac02011-06-13 14:46:52 +000084 memcpy(dst, src, 16 * sizeof(float));
85#endif
86}
87
88void SkMatrix44::asColMajord(double dst[]) const {
89 const SkMScalar* src = &fMat[0][0];
90#ifdef SK_MSCALAR_IS_DOUBLE
91 memcpy(dst, src, 16 * sizeof(double));
vollick@chromium.org5596a692012-11-13 20:12:00 +000092#elif defined SK_MSCALAR_IS_FLOAT
reed@google.comda9fac02011-06-13 14:46:52 +000093 for (int i = 0; i < 16; ++i) {
94 dst[i] = SkMScalarToDouble(src[i]);
95 }
96#endif
97}
98
99void SkMatrix44::asRowMajorf(float dst[]) const {
100 const SkMScalar* src = &fMat[0][0];
101 for (int i = 0; i < 4; ++i) {
102 dst[0] = SkMScalarToFloat(src[0]);
103 dst[4] = SkMScalarToFloat(src[1]);
104 dst[8] = SkMScalarToFloat(src[2]);
105 dst[12] = SkMScalarToFloat(src[3]);
106 src += 4;
107 dst += 1;
108 }
109}
110
111void SkMatrix44::asRowMajord(double dst[]) const {
112 const SkMScalar* src = &fMat[0][0];
113 for (int i = 0; i < 4; ++i) {
114 dst[0] = SkMScalarToDouble(src[0]);
115 dst[4] = SkMScalarToDouble(src[1]);
116 dst[8] = SkMScalarToDouble(src[2]);
117 dst[12] = SkMScalarToDouble(src[3]);
118 src += 4;
119 dst += 1;
120 }
121}
122
vollick@chromium.orgf11cf9f2012-11-19 21:02:06 +0000123void SkMatrix44::setColMajorf(const float src[]) {
124 SkMScalar* dst = &fMat[0][0];
125#ifdef SK_MSCALAR_IS_DOUBLE
126 for (int i = 0; i < 16; ++i) {
127 dst[i] = SkMScalarToFloat(src[i]);
128 }
129#elif defined SK_MSCALAR_IS_FLOAT
130 memcpy(dst, src, 16 * sizeof(float));
131#endif
reed@google.com7d683352012-12-03 21:19:52 +0000132
133 this->dirtyTypeMask();
vollick@chromium.orgf11cf9f2012-11-19 21:02:06 +0000134}
135
136void SkMatrix44::setColMajord(const double src[]) {
137 SkMScalar* dst = &fMat[0][0];
138#ifdef SK_MSCALAR_IS_DOUBLE
139 memcpy(dst, src, 16 * sizeof(double));
140#elif defined SK_MSCALAR_IS_FLOAT
141 for (int i = 0; i < 16; ++i) {
robertphillips@google.com93f03322012-12-03 17:35:19 +0000142 dst[i] = SkDoubleToMScalar(src[i]);
vollick@chromium.orgf11cf9f2012-11-19 21:02:06 +0000143 }
144#endif
reed@google.com7d683352012-12-03 21:19:52 +0000145
146 this->dirtyTypeMask();
vollick@chromium.orgf11cf9f2012-11-19 21:02:06 +0000147}
148
149void SkMatrix44::setRowMajorf(const float src[]) {
150 SkMScalar* dst = &fMat[0][0];
151 for (int i = 0; i < 4; ++i) {
152 dst[0] = SkMScalarToFloat(src[0]);
153 dst[4] = SkMScalarToFloat(src[1]);
154 dst[8] = SkMScalarToFloat(src[2]);
155 dst[12] = SkMScalarToFloat(src[3]);
156 src += 4;
157 dst += 1;
158 }
reed@google.com7d683352012-12-03 21:19:52 +0000159 this->dirtyTypeMask();
vollick@chromium.orgf11cf9f2012-11-19 21:02:06 +0000160}
161
162void SkMatrix44::setRowMajord(const double src[]) {
163 SkMScalar* dst = &fMat[0][0];
164 for (int i = 0; i < 4; ++i) {
robertphillips@google.com93f03322012-12-03 17:35:19 +0000165 dst[0] = SkDoubleToMScalar(src[0]);
166 dst[4] = SkDoubleToMScalar(src[1]);
167 dst[8] = SkDoubleToMScalar(src[2]);
168 dst[12] = SkDoubleToMScalar(src[3]);
vollick@chromium.orgf11cf9f2012-11-19 21:02:06 +0000169 src += 4;
170 dst += 1;
171 }
reed@google.com7d683352012-12-03 21:19:52 +0000172 this->dirtyTypeMask();
vollick@chromium.orgf11cf9f2012-11-19 21:02:06 +0000173}
174
reed@google.comda9fac02011-06-13 14:46:52 +0000175///////////////////////////////////////////////////////////////////////////////
176
reed@google.com7d683352012-12-03 21:19:52 +0000177const SkMatrix44& SkMatrix44::I() {
reed@google.com1adad342012-12-10 21:21:27 +0000178 static const SkMatrix44 gIdentity44(kIdentity_Constructor);
179 return gIdentity44;
reed@google.com8260a892011-06-13 14:02:52 +0000180}
181
reed@google.com8260a892011-06-13 14:02:52 +0000182void SkMatrix44::setIdentity() {
183 sk_bzero(fMat, sizeof(fMat));
184 fMat[0][0] = fMat[1][1] = fMat[2][2] = fMat[3][3] = 1;
reed@google.com7d683352012-12-03 21:19:52 +0000185 this->setTypeMask(kIdentity_Mask);
reed@google.com8260a892011-06-13 14:02:52 +0000186}
187
188void SkMatrix44::set3x3(SkMScalar m00, SkMScalar m01, SkMScalar m02,
189 SkMScalar m10, SkMScalar m11, SkMScalar m12,
190 SkMScalar m20, SkMScalar m21, SkMScalar m22) {
reed@google.com8260a892011-06-13 14:02:52 +0000191 fMat[0][0] = m00; fMat[0][1] = m01; fMat[0][2] = m02; fMat[0][3] = 0;
192 fMat[1][0] = m10; fMat[1][1] = m11; fMat[1][2] = m12; fMat[1][3] = 0;
193 fMat[2][0] = m20; fMat[2][1] = m21; fMat[2][2] = m22; fMat[2][3] = 0;
194 fMat[3][0] = 0; fMat[3][1] = 0; fMat[3][2] = 0; fMat[3][3] = 1;
reed@google.com7d683352012-12-03 21:19:52 +0000195 this->dirtyTypeMask();
reed@google.com8260a892011-06-13 14:02:52 +0000196}
197
198///////////////////////////////////////////////////////////////////////////////
199
reed@google.com99b5c7f2012-12-05 22:13:59 +0000200void SkMatrix44::setTranslate(SkMScalar dx, SkMScalar dy, SkMScalar dz) {
reed@google.com8260a892011-06-13 14:02:52 +0000201 this->setIdentity();
skia.committer@gmail.come659c2e2012-12-04 02:01:25 +0000202
reed@google.com99b5c7f2012-12-05 22:13:59 +0000203 if (!dx && !dy && !dz) {
204 return;
reed@google.com7d683352012-12-03 21:19:52 +0000205 }
skia.committer@gmail.com0264fb42012-12-06 02:01:25 +0000206
reed@google.com99b5c7f2012-12-05 22:13:59 +0000207 fMat[3][0] = dx;
208 fMat[3][1] = dy;
209 fMat[3][2] = dz;
210 this->setTypeMask(kTranslate_Mask);
reed@google.com8260a892011-06-13 14:02:52 +0000211}
212
213void SkMatrix44::preTranslate(SkMScalar dx, SkMScalar dy, SkMScalar dz) {
reed@google.com99b5c7f2012-12-05 22:13:59 +0000214 if (!dx && !dy && !dz) {
215 return;
216 }
217
218 const double X = SkMScalarToDouble(dx);
219 const double Y = SkMScalarToDouble(dy);
220 const double Z = SkMScalarToDouble(dz);
221
222 double tmp;
223 for (int i = 0; i < 4; ++i) {
224 tmp = fMat[0][i] * X + fMat[1][i] * Y + fMat[2][i] * Z + fMat[3][i];
225 fMat[3][i] = SkDoubleToMScalar(tmp);
226 }
227 this->dirtyTypeMask();
reed@google.com8260a892011-06-13 14:02:52 +0000228}
229
230void SkMatrix44::postTranslate(SkMScalar dx, SkMScalar dy, SkMScalar dz) {
reed@google.com99b5c7f2012-12-05 22:13:59 +0000231 if (!dx && !dy && !dz) {
232 return;
233 }
234
235 if (this->getType() & kPerspective_Mask) {
236 for (int i = 0; i < 4; ++i) {
237 fMat[i][0] += fMat[i][3] * dx;
238 fMat[i][1] += fMat[i][3] * dy;
239 fMat[i][2] += fMat[i][3] * dz;
240 }
241 } else {
242 fMat[3][0] += dx;
243 fMat[3][1] += dy;
244 fMat[3][2] += dz;
245 this->dirtyTypeMask();
246 }
reed@google.com8260a892011-06-13 14:02:52 +0000247}
248
249///////////////////////////////////////////////////////////////////////////////
250
251void SkMatrix44::setScale(SkMScalar sx, SkMScalar sy, SkMScalar sz) {
reed@google.com99b5c7f2012-12-05 22:13:59 +0000252 this->setIdentity();
253
254 if (1 == sx && 1 == sy && 1 == sz) {
255 return;
256 }
257
reed@google.com8260a892011-06-13 14:02:52 +0000258 fMat[0][0] = sx;
259 fMat[1][1] = sy;
260 fMat[2][2] = sz;
reed@google.com99b5c7f2012-12-05 22:13:59 +0000261 this->setTypeMask(kScale_Mask);
reed@google.com8260a892011-06-13 14:02:52 +0000262}
263
264void SkMatrix44::preScale(SkMScalar sx, SkMScalar sy, SkMScalar sz) {
reed@google.com99b5c7f2012-12-05 22:13:59 +0000265 if (1 == sx && 1 == sy && 1 == sz) {
266 return;
267 }
skia.committer@gmail.com0264fb42012-12-06 02:01:25 +0000268
shawnsingh@chromium.orgf81f97e2012-12-13 22:21:36 +0000269 // The implementation matrix * pureScale can be shortcut
270 // by knowing that pureScale components effectively scale
271 // the columns of the original matrix.
272 for (int i = 0; i < 4; i++) {
273 fMat[0][i] *= sx;
274 fMat[1][i] *= sy;
275 fMat[2][i] *= sz;
276 }
277 this->dirtyTypeMask();
reed@google.com8260a892011-06-13 14:02:52 +0000278}
279
280void SkMatrix44::postScale(SkMScalar sx, SkMScalar sy, SkMScalar sz) {
reed@google.com99b5c7f2012-12-05 22:13:59 +0000281 if (1 == sx && 1 == sy && 1 == sz) {
282 return;
283 }
skia.committer@gmail.com0264fb42012-12-06 02:01:25 +0000284
reed@google.com8260a892011-06-13 14:02:52 +0000285 for (int i = 0; i < 4; i++) {
286 fMat[i][0] *= sx;
287 fMat[i][1] *= sy;
288 fMat[i][2] *= sz;
289 }
reed@google.com7d683352012-12-03 21:19:52 +0000290 this->dirtyTypeMask();
reed@google.com8260a892011-06-13 14:02:52 +0000291}
292
293///////////////////////////////////////////////////////////////////////////////
294
295void SkMatrix44::setRotateAbout(SkMScalar x, SkMScalar y, SkMScalar z,
296 SkMScalar radians) {
reed@google.com7d683352012-12-03 21:19:52 +0000297 double len2 = (double)x * x + (double)y * y + (double)z * z;
298 if (1 != len2) {
299 if (0 == len2) {
reed@google.com8260a892011-06-13 14:02:52 +0000300 this->setIdentity();
301 return;
302 }
303 double scale = 1 / sqrt(len2);
bsalomon@google.com9d12f5c2011-09-29 18:08:18 +0000304 x = SkDoubleToMScalar(x * scale);
305 y = SkDoubleToMScalar(y * scale);
306 z = SkDoubleToMScalar(z * scale);
reed@google.com8260a892011-06-13 14:02:52 +0000307 }
308 this->setRotateAboutUnit(x, y, z, radians);
309}
310
311void SkMatrix44::setRotateAboutUnit(SkMScalar x, SkMScalar y, SkMScalar z,
312 SkMScalar radians) {
313 double c = cos(radians);
314 double s = sin(radians);
315 double C = 1 - c;
316 double xs = x * s;
317 double ys = y * s;
318 double zs = z * s;
319 double xC = x * C;
320 double yC = y * C;
321 double zC = z * C;
322 double xyC = x * yC;
323 double yzC = y * zC;
324 double zxC = z * xC;
325
326 // if you're looking at wikipedia, remember that we're column major.
bsalomon@google.com9d12f5c2011-09-29 18:08:18 +0000327 this->set3x3(SkDoubleToMScalar(x * xC + c), // scale x
328 SkDoubleToMScalar(xyC + zs), // skew x
329 SkDoubleToMScalar(zxC - ys), // trans x
330
331 SkDoubleToMScalar(xyC - zs), // skew y
332 SkDoubleToMScalar(y * yC + c), // scale y
333 SkDoubleToMScalar(yzC + xs), // trans y
334
335 SkDoubleToMScalar(zxC + ys), // persp x
336 SkDoubleToMScalar(yzC - xs), // persp y
337 SkDoubleToMScalar(z * zC + c)); // persp 2
reed@google.com8260a892011-06-13 14:02:52 +0000338}
339
340///////////////////////////////////////////////////////////////////////////////
341
reed@google.com99b5c7f2012-12-05 22:13:59 +0000342static bool bits_isonly(int value, int mask) {
343 return 0 == (value & ~mask);
344}
345
reed@google.com8260a892011-06-13 14:02:52 +0000346void SkMatrix44::setConcat(const SkMatrix44& a, const SkMatrix44& b) {
reed@google.com99b5c7f2012-12-05 22:13:59 +0000347 const SkMatrix44::TypeMask a_mask = a.getType();
348 const SkMatrix44::TypeMask b_mask = b.getType();
349
350 if (kIdentity_Mask == a_mask) {
reed@google.com7d683352012-12-03 21:19:52 +0000351 *this = b;
352 return;
353 }
reed@google.com99b5c7f2012-12-05 22:13:59 +0000354 if (kIdentity_Mask == b_mask) {
reed@google.com7d683352012-12-03 21:19:52 +0000355 *this = a;
356 return;
357 }
358
359 bool useStorage = (this == &a || this == &b);
360 SkMScalar storage[16];
361 SkMScalar* result = useStorage ? storage : &fMat[0][0];
362
reed@google.com2b165702013-01-17 16:01:19 +0000363 // Both matrices are at most scale+translate
reed@google.com99b5c7f2012-12-05 22:13:59 +0000364 if (bits_isonly(a_mask | b_mask, kScale_Mask | kTranslate_Mask)) {
reed@google.com99b5c7f2012-12-05 22:13:59 +0000365 result[0] = a.fMat[0][0] * b.fMat[0][0];
reed@google.com2b165702013-01-17 16:01:19 +0000366 result[1] = result[2] = result[3] = result[4] = 0;
reed@google.com99b5c7f2012-12-05 22:13:59 +0000367 result[5] = a.fMat[1][1] * b.fMat[1][1];
reed@google.com2b165702013-01-17 16:01:19 +0000368 result[6] = result[7] = result[8] = result[9] = 0;
reed@google.com99b5c7f2012-12-05 22:13:59 +0000369 result[10] = a.fMat[2][2] * b.fMat[2][2];
reed@google.com2b165702013-01-17 16:01:19 +0000370 result[11] = 0;
reed@google.com99b5c7f2012-12-05 22:13:59 +0000371 result[12] = a.fMat[0][0] * b.fMat[3][0] + a.fMat[3][0];
372 result[13] = a.fMat[1][1] * b.fMat[3][1] + a.fMat[3][1];
373 result[14] = a.fMat[2][2] * b.fMat[3][2] + a.fMat[3][2];
374 result[15] = 1;
375 } else {
376 for (int j = 0; j < 4; j++) {
377 for (int i = 0; i < 4; i++) {
378 double value = 0;
379 for (int k = 0; k < 4; k++) {
380 value += SkMScalarToDouble(a.fMat[k][i]) * b.fMat[j][k];
381 }
382 *result++ = SkDoubleToMScalar(value);
reed@google.com8260a892011-06-13 14:02:52 +0000383 }
reed@google.com8260a892011-06-13 14:02:52 +0000384 }
385 }
reed@google.com99b5c7f2012-12-05 22:13:59 +0000386
reed@google.com7d683352012-12-03 21:19:52 +0000387 if (useStorage) {
tomhudson@google.com7cfb9c72013-01-17 13:29:35 +0000388 memcpy(fMat, storage, sizeof(storage));
reed@google.com7d683352012-12-03 21:19:52 +0000389 }
reed@google.com7d683352012-12-03 21:19:52 +0000390 this->dirtyTypeMask();
reed@google.com8260a892011-06-13 14:02:52 +0000391}
392
393///////////////////////////////////////////////////////////////////////////////
394
395static inline SkMScalar det2x2(double m00, double m01, double m10, double m11) {
bsalomon@google.com9d12f5c2011-09-29 18:08:18 +0000396 return SkDoubleToMScalar(m00 * m11 - m10 * m01);
reed@google.com8260a892011-06-13 14:02:52 +0000397}
398
399static inline double det3x3(double m00, double m01, double m02,
400 double m10, double m11, double m12,
401 double m20, double m21, double m22) {
402 return m00 * det2x2(m11, m12, m21, m22) -
403 m10 * det2x2(m01, m02, m21, m22) +
404 m20 * det2x2(m01, m02, m11, m12);
405}
406
407/** We always perform the calculation in doubles, to avoid prematurely losing
408 precision along the way. This relies on the compiler automatically
409 promoting our SkMScalar values to double (if needed).
410 */
411double SkMatrix44::determinant() const {
mike@reedtribe.orgf8b1ebc2012-12-10 03:27:47 +0000412 if (this->isIdentity()) {
413 return 1;
414 }
415 if (this->isScaleTranslate()) {
416 return fMat[0][0] * fMat[1][1] * fMat[2][2] * fMat[3][3];
417 }
418
tomhudson@google.com9973a8a2012-12-13 09:55:42 +0000419 double a00 = fMat[0][0];
420 double a01 = fMat[0][1];
421 double a02 = fMat[0][2];
422 double a03 = fMat[0][3];
423 double a10 = fMat[1][0];
424 double a11 = fMat[1][1];
425 double a12 = fMat[1][2];
426 double a13 = fMat[1][3];
427 double a20 = fMat[2][0];
428 double a21 = fMat[2][1];
429 double a22 = fMat[2][2];
430 double a23 = fMat[2][3];
431 double a30 = fMat[3][0];
432 double a31 = fMat[3][1];
433 double a32 = fMat[3][2];
434 double a33 = fMat[3][3];
435
436 double b00 = a00 * a11 - a01 * a10;
437 double b01 = a00 * a12 - a02 * a10;
438 double b02 = a00 * a13 - a03 * a10;
439 double b03 = a01 * a12 - a02 * a11;
440 double b04 = a01 * a13 - a03 * a11;
441 double b05 = a02 * a13 - a03 * a12;
442 double b06 = a20 * a31 - a21 * a30;
443 double b07 = a20 * a32 - a22 * a30;
444 double b08 = a20 * a33 - a23 * a30;
445 double b09 = a21 * a32 - a22 * a31;
446 double b10 = a21 * a33 - a23 * a31;
447 double b11 = a22 * a33 - a23 * a32;
448
449 // Calculate the determinant
450 return b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
reed@google.com8260a892011-06-13 14:02:52 +0000451}
452
453///////////////////////////////////////////////////////////////////////////////
454
455// just picked a small value. not sure how to pick the "right" one
456#define TOO_SMALL_FOR_DETERMINANT (1.e-8)
457
458static inline double dabs(double x) {
459 if (x < 0) {
460 x = -x;
461 }
462 return x;
463}
464
465bool SkMatrix44::invert(SkMatrix44* inverse) const {
mike@reedtribe.orgf8b1ebc2012-12-10 03:27:47 +0000466 if (this->isIdentity()) {
reed@google.com7d683352012-12-03 21:19:52 +0000467 if (inverse) {
468 *inverse = *this;
469 return true;
470 }
471 }
mike@reedtribe.orgf8b1ebc2012-12-10 03:27:47 +0000472 if (this->isTranslate()) {
reed@google.com99b5c7f2012-12-05 22:13:59 +0000473 if (inverse) {
474 inverse->setTranslate(-fMat[3][0], -fMat[3][1], -fMat[3][2]);
475 }
476 return true;
477 }
mike@reedtribe.orgf8b1ebc2012-12-10 03:27:47 +0000478 if (this->isScaleTranslate()) {
reed@google.com99b5c7f2012-12-05 22:13:59 +0000479 if (0 == fMat[0][0] * fMat[1][1] * fMat[2][2]) {
480 return false;
481 }
482 if (inverse) {
483 sk_bzero(inverse->fMat, sizeof(inverse->fMat));
484
shawnsingh@chromium.orgb6823c12013-08-22 20:24:21 +0000485 double invXScale = 1 / fMat[0][0];
486 double invYScale = 1 / fMat[1][1];
487 double invZScale = 1 / fMat[2][2];
reed@google.com99b5c7f2012-12-05 22:13:59 +0000488
shawnsingh@chromium.orgb6823c12013-08-22 20:24:21 +0000489 inverse->fMat[3][0] = -fMat[3][0] * invXScale;
490 inverse->fMat[3][1] = -fMat[3][1] * invYScale;
491 inverse->fMat[3][2] = -fMat[3][2] * invZScale;
492
493 inverse->fMat[0][0] = invXScale;
494 inverse->fMat[1][1] = invYScale;
495 inverse->fMat[2][2] = invZScale;
reed@google.com99b5c7f2012-12-05 22:13:59 +0000496 inverse->fMat[3][3] = 1;
497
mike@reedtribe.orgf8b1ebc2012-12-10 03:27:47 +0000498 inverse->setTypeMask(this->getType());
reed@google.com99b5c7f2012-12-05 22:13:59 +0000499 }
500 return true;
501 }
502
tomhudson@google.com9973a8a2012-12-13 09:55:42 +0000503 double a00 = fMat[0][0];
504 double a01 = fMat[0][1];
505 double a02 = fMat[0][2];
506 double a03 = fMat[0][3];
507 double a10 = fMat[1][0];
508 double a11 = fMat[1][1];
509 double a12 = fMat[1][2];
510 double a13 = fMat[1][3];
511 double a20 = fMat[2][0];
512 double a21 = fMat[2][1];
513 double a22 = fMat[2][2];
514 double a23 = fMat[2][3];
515 double a30 = fMat[3][0];
516 double a31 = fMat[3][1];
517 double a32 = fMat[3][2];
518 double a33 = fMat[3][3];
519
shawnsingh@chromium.orgb6823c12013-08-22 20:24:21 +0000520 if (!(this->getType() & kPerspective_Mask)) {
521 // If we know the matrix has no perspective, then the perspective
522 // component is (0, 0, 0, 1). We can use this information to save a lot
523 // of arithmetic that would otherwise be spent to compute the inverse
524 // of a general matrix.
525
526 SkASSERT(a03 == 0);
527 SkASSERT(a13 == 0);
528 SkASSERT(a23 == 0);
529 SkASSERT(a33 == 1);
530
531 double b00 = a00 * a11 - a01 * a10;
532 double b01 = a00 * a12 - a02 * a10;
533 double b03 = a01 * a12 - a02 * a11;
534 double b06 = a20 * a31 - a21 * a30;
535 double b07 = a20 * a32 - a22 * a30;
536 double b08 = a20;
537 double b09 = a21 * a32 - a22 * a31;
538 double b10 = a21;
539 double b11 = a22;
540
541 // Calculate the determinant
542 double det = b00 * b11 - b01 * b10 + b03 * b08;
543
544 double invdet = 1.0 / det;
545 // If det is zero, we want to return false. However, we also want to return false
546 // if 1/det overflows to infinity (i.e. det is denormalized). Both of these are
547 // handled by checking that 1/det is finite.
548 if (!sk_float_isfinite(invdet)) {
549 return false;
550 }
551 if (NULL == inverse) {
552 return true;
553 }
554
555 b00 *= invdet;
556 b01 *= invdet;
557 b03 *= invdet;
558 b06 *= invdet;
559 b07 *= invdet;
560 b08 *= invdet;
561 b09 *= invdet;
562 b10 *= invdet;
563 b11 *= invdet;
564
565 inverse->fMat[0][0] = SkDoubleToMScalar(a11 * b11 - a12 * b10);
566 inverse->fMat[0][1] = SkDoubleToMScalar(a02 * b10 - a01 * b11);
567 inverse->fMat[0][2] = SkDoubleToMScalar(b03);
568 inverse->fMat[0][3] = 0;
569 inverse->fMat[1][0] = SkDoubleToMScalar(a12 * b08 - a10 * b11);
570 inverse->fMat[1][1] = SkDoubleToMScalar(a00 * b11 - a02 * b08);
571 inverse->fMat[1][2] = SkDoubleToMScalar(-b01);
572 inverse->fMat[1][3] = 0;
573 inverse->fMat[2][0] = SkDoubleToMScalar(a10 * b10 - a11 * b08);
574 inverse->fMat[2][1] = SkDoubleToMScalar(a01 * b08 - a00 * b10);
575 inverse->fMat[2][2] = SkDoubleToMScalar(b00);
576 inverse->fMat[2][3] = 0;
577 inverse->fMat[3][0] = SkDoubleToMScalar(a11 * b07 - a10 * b09 - a12 * b06);
578 inverse->fMat[3][1] = SkDoubleToMScalar(a00 * b09 - a01 * b07 + a02 * b06);
579 inverse->fMat[3][2] = SkDoubleToMScalar(a31 * b01 - a30 * b03 - a32 * b00);
580 inverse->fMat[3][3] = 1;
581
582 inverse->setTypeMask(this->getType());
583 return true;
584 }
585
tomhudson@google.com9973a8a2012-12-13 09:55:42 +0000586 double b00 = a00 * a11 - a01 * a10;
587 double b01 = a00 * a12 - a02 * a10;
588 double b02 = a00 * a13 - a03 * a10;
589 double b03 = a01 * a12 - a02 * a11;
590 double b04 = a01 * a13 - a03 * a11;
591 double b05 = a02 * a13 - a03 * a12;
592 double b06 = a20 * a31 - a21 * a30;
593 double b07 = a20 * a32 - a22 * a30;
594 double b08 = a20 * a33 - a23 * a30;
595 double b09 = a21 * a32 - a22 * a31;
596 double b10 = a21 * a33 - a23 * a31;
597 double b11 = a22 * a33 - a23 * a32;
598
599 // Calculate the determinant
600 double det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
601
commit-bot@chromium.orgf02f0782013-08-20 15:25:04 +0000602 double invdet = 1.0 / det;
603 // If det is zero, we want to return false. However, we also want to return false
604 // if 1/det overflows to infinity (i.e. det is denormalized). Both of these are
605 // handled by checking that 1/det is finite.
606 if (!sk_float_isfinite(invdet)) {
reed@google.com8260a892011-06-13 14:02:52 +0000607 return false;
608 }
609 if (NULL == inverse) {
610 return true;
611 }
612
tomhudson@google.com9973a8a2012-12-13 09:55:42 +0000613 b00 *= invdet;
614 b01 *= invdet;
615 b02 *= invdet;
616 b03 *= invdet;
617 b04 *= invdet;
618 b05 *= invdet;
619 b06 *= invdet;
620 b07 *= invdet;
621 b08 *= invdet;
622 b09 *= invdet;
623 b10 *= invdet;
624 b11 *= invdet;
reed@google.com8260a892011-06-13 14:02:52 +0000625
tomhudson@google.com9973a8a2012-12-13 09:55:42 +0000626 inverse->fMat[0][0] = SkDoubleToMScalar(a11 * b11 - a12 * b10 + a13 * b09);
627 inverse->fMat[0][1] = SkDoubleToMScalar(a02 * b10 - a01 * b11 - a03 * b09);
628 inverse->fMat[0][2] = SkDoubleToMScalar(a31 * b05 - a32 * b04 + a33 * b03);
629 inverse->fMat[0][3] = SkDoubleToMScalar(a22 * b04 - a21 * b05 - a23 * b03);
630 inverse->fMat[1][0] = SkDoubleToMScalar(a12 * b08 - a10 * b11 - a13 * b07);
631 inverse->fMat[1][1] = SkDoubleToMScalar(a00 * b11 - a02 * b08 + a03 * b07);
632 inverse->fMat[1][2] = SkDoubleToMScalar(a32 * b02 - a30 * b05 - a33 * b01);
633 inverse->fMat[1][3] = SkDoubleToMScalar(a20 * b05 - a22 * b02 + a23 * b01);
634 inverse->fMat[2][0] = SkDoubleToMScalar(a10 * b10 - a11 * b08 + a13 * b06);
635 inverse->fMat[2][1] = SkDoubleToMScalar(a01 * b08 - a00 * b10 - a03 * b06);
636 inverse->fMat[2][2] = SkDoubleToMScalar(a30 * b04 - a31 * b02 + a33 * b00);
637 inverse->fMat[2][3] = SkDoubleToMScalar(a21 * b02 - a20 * b04 - a23 * b00);
638 inverse->fMat[3][0] = SkDoubleToMScalar(a11 * b07 - a10 * b09 - a12 * b06);
639 inverse->fMat[3][1] = SkDoubleToMScalar(a00 * b09 - a01 * b07 + a02 * b06);
640 inverse->fMat[3][2] = SkDoubleToMScalar(a31 * b01 - a30 * b03 - a32 * b00);
641 inverse->fMat[3][3] = SkDoubleToMScalar(a20 * b03 - a21 * b01 + a22 * b00);
642 inverse->dirtyTypeMask();
reed@google.com8260a892011-06-13 14:02:52 +0000643
reed@google.com8260a892011-06-13 14:02:52 +0000644 return true;
645}
646
647///////////////////////////////////////////////////////////////////////////////
648
vollick@chromium.org9b21c252012-11-14 21:33:55 +0000649void SkMatrix44::transpose() {
650 SkTSwap(fMat[0][1], fMat[1][0]);
651 SkTSwap(fMat[0][2], fMat[2][0]);
652 SkTSwap(fMat[0][3], fMat[3][0]);
653 SkTSwap(fMat[1][2], fMat[2][1]);
654 SkTSwap(fMat[1][3], fMat[3][1]);
655 SkTSwap(fMat[2][3], fMat[3][2]);
reed@google.com7d683352012-12-03 21:19:52 +0000656
657 if (!this->isTriviallyIdentity()) {
658 this->dirtyTypeMask();
659 }
vollick@chromium.org9b21c252012-11-14 21:33:55 +0000660}
661
662///////////////////////////////////////////////////////////////////////////////
663
reed@google.com1ea95be2012-11-09 21:39:48 +0000664void SkMatrix44::mapScalars(const SkScalar src[4], SkScalar dst[4]) const {
reed@google.com7d683352012-12-03 21:19:52 +0000665 SkScalar storage[4];
666 SkScalar* result = (src == dst) ? storage : dst;
667
reed@google.com8260a892011-06-13 14:02:52 +0000668 for (int i = 0; i < 4; i++) {
669 SkMScalar value = 0;
670 for (int j = 0; j < 4; j++) {
671 value += fMat[j][i] * src[j];
672 }
bsalomon@google.com72e49b82011-10-27 21:47:03 +0000673 result[i] = SkMScalarToScalar(value);
reed@google.com8260a892011-06-13 14:02:52 +0000674 }
skia.committer@gmail.com0264fb42012-12-06 02:01:25 +0000675
reed@google.com7d683352012-12-03 21:19:52 +0000676 if (storage == result) {
677 memcpy(dst, storage, sizeof(storage));
678 }
reed@google.com8260a892011-06-13 14:02:52 +0000679}
680
reed@google.com1ea95be2012-11-09 21:39:48 +0000681#ifdef SK_MSCALAR_IS_DOUBLE
reed@google.com7d683352012-12-03 21:19:52 +0000682
reed@google.com1ea95be2012-11-09 21:39:48 +0000683void SkMatrix44::mapMScalars(const SkMScalar src[4], SkMScalar dst[4]) const {
reed@google.com7d683352012-12-03 21:19:52 +0000684 SkMScalar storage[4];
685 SkMScalar* result = (src == dst) ? storage : dst;
skia.committer@gmail.com0264fb42012-12-06 02:01:25 +0000686
reed@google.com1ea95be2012-11-09 21:39:48 +0000687 for (int i = 0; i < 4; i++) {
688 SkMScalar value = 0;
689 for (int j = 0; j < 4; j++) {
690 value += fMat[j][i] * src[j];
691 }
reed@google.com7d683352012-12-03 21:19:52 +0000692 result[i] = value;
reed@google.com1ea95be2012-11-09 21:39:48 +0000693 }
skia.committer@gmail.com0264fb42012-12-06 02:01:25 +0000694
reed@google.com7d683352012-12-03 21:19:52 +0000695 if (storage == result) {
696 memcpy(dst, storage, sizeof(storage));
697 }
reed@google.com1ea95be2012-11-09 21:39:48 +0000698}
reed@google.com7d683352012-12-03 21:19:52 +0000699
reed@google.com1ea95be2012-11-09 21:39:48 +0000700#endif
701
reed@google.com99b5c7f2012-12-05 22:13:59 +0000702typedef void (*Map2Procf)(const SkMScalar mat[][4], const float src2[], int count, float dst4[]);
703typedef void (*Map2Procd)(const SkMScalar mat[][4], const double src2[], int count, double dst4[]);
704
705static void map2_if(const SkMScalar mat[][4], const float* SK_RESTRICT src2,
706 int count, float* SK_RESTRICT dst4) {
707 for (int i = 0; i < count; ++i) {
708 dst4[0] = src2[0];
709 dst4[1] = src2[1];
710 dst4[2] = 0;
711 dst4[3] = 1;
712 src2 += 2;
713 dst4 += 4;
714 }
715}
716
717static void map2_id(const SkMScalar mat[][4], const double* SK_RESTRICT src2,
718 int count, double* SK_RESTRICT dst4) {
719 for (int i = 0; i < count; ++i) {
720 dst4[0] = src2[0];
721 dst4[1] = src2[1];
722 dst4[2] = 0;
723 dst4[3] = 1;
724 src2 += 2;
725 dst4 += 4;
726 }
727}
728
729static void map2_tf(const SkMScalar mat[][4], const float* SK_RESTRICT src2,
730 int count, float* SK_RESTRICT dst4) {
731 const float mat30 = SkMScalarToFloat(mat[3][0]);
732 const float mat31 = SkMScalarToFloat(mat[3][1]);
733 const float mat32 = SkMScalarToFloat(mat[3][2]);
734 for (int n = 0; n < count; ++n) {
735 dst4[0] = src2[0] + mat30;
736 dst4[1] = src2[1] + mat31;
737 dst4[2] = mat32;
738 dst4[3] = 1;
739 src2 += 2;
740 dst4 += 4;
741 }
742}
743
744static void map2_td(const SkMScalar mat[][4], const double* SK_RESTRICT src2,
745 int count, double* SK_RESTRICT dst4) {
746 for (int n = 0; n < count; ++n) {
747 dst4[0] = src2[0] + mat[3][0];
748 dst4[1] = src2[1] + mat[3][1];
749 dst4[2] = mat[3][2];
750 dst4[3] = 1;
751 src2 += 2;
752 dst4 += 4;
753 }
754}
755
756static void map2_sf(const SkMScalar mat[][4], const float* SK_RESTRICT src2,
757 int count, float* SK_RESTRICT dst4) {
758 const float mat32 = SkMScalarToFloat(mat[3][2]);
759 for (int n = 0; n < count; ++n) {
760 dst4[0] = SkMScalarToFloat(mat[0][0] * src2[0] + mat[3][0]);
761 dst4[1] = SkMScalarToFloat(mat[1][1] * src2[1] + mat[3][1]);
762 dst4[2] = mat32;
763 dst4[3] = 1;
764 src2 += 2;
765 dst4 += 4;
766 }
767}
768
769static void map2_sd(const SkMScalar mat[][4], const double* SK_RESTRICT src2,
770 int count, double* SK_RESTRICT dst4) {
771 for (int n = 0; n < count; ++n) {
772 dst4[0] = mat[0][0] * src2[0] + mat[3][0];
773 dst4[1] = mat[1][1] * src2[1] + mat[3][1];
774 dst4[2] = mat[3][2];
775 dst4[3] = 1;
776 src2 += 2;
777 dst4 += 4;
778 }
779}
780
781static void map2_af(const SkMScalar mat[][4], const float* SK_RESTRICT src2,
782 int count, float* SK_RESTRICT dst4) {
783 double r;
784 for (int n = 0; n < count; ++n) {
785 double sx = src2[0];
786 double sy = src2[1];
787 r = mat[0][0] * sx + mat[1][0] * sy + mat[3][0];
788 dst4[0] = SkMScalarToFloat(r);
789 r = mat[0][1] * sx + mat[1][1] * sy + mat[3][1];
790 dst4[1] = SkMScalarToFloat(r);
791 r = mat[0][2] * sx + mat[1][2] * sy + mat[3][2];
792 dst4[2] = SkMScalarToFloat(r);
793 dst4[3] = 1;
794 src2 += 2;
795 dst4 += 4;
796 }
797}
798
799static void map2_ad(const SkMScalar mat[][4], const double* SK_RESTRICT src2,
800 int count, double* SK_RESTRICT dst4) {
801 for (int n = 0; n < count; ++n) {
802 double sx = src2[0];
803 double sy = src2[1];
804 dst4[0] = mat[0][0] * sx + mat[1][0] * sy + mat[3][0];
805 dst4[1] = mat[0][1] * sx + mat[1][1] * sy + mat[3][1];
806 dst4[2] = mat[0][2] * sx + mat[1][2] * sy + mat[3][2];
807 dst4[3] = 1;
808 src2 += 2;
809 dst4 += 4;
810 }
811}
812
813static void map2_pf(const SkMScalar mat[][4], const float* SK_RESTRICT src2,
814 int count, float* SK_RESTRICT dst4) {
815 double r;
816 for (int n = 0; n < count; ++n) {
817 double sx = src2[0];
818 double sy = src2[1];
819 for (int i = 0; i < 4; i++) {
820 r = mat[0][i] * sx + mat[1][i] * sy + mat[3][i];
821 dst4[i] = SkMScalarToFloat(r);
822 }
823 src2 += 2;
824 dst4 += 4;
825 }
826}
827
828static void map2_pd(const SkMScalar mat[][4], const double* SK_RESTRICT src2,
829 int count, double* SK_RESTRICT dst4) {
830 for (int n = 0; n < count; ++n) {
831 double sx = src2[0];
832 double sy = src2[1];
833 for (int i = 0; i < 4; i++) {
834 dst4[i] = mat[0][i] * sx + mat[1][i] * sy + mat[3][i];
835 }
836 src2 += 2;
837 dst4 += 4;
838 }
839}
840
841void SkMatrix44::map2(const float src2[], int count, float dst4[]) const {
842 static const Map2Procf gProc[] = {
843 map2_if, map2_tf, map2_sf, map2_sf, map2_af, map2_af, map2_af, map2_af
844 };
845
846 TypeMask mask = this->getType();
847 Map2Procf proc = (mask & kPerspective_Mask) ? map2_pf : gProc[mask];
848 proc(fMat, src2, count, dst4);
849}
850
851void SkMatrix44::map2(const double src2[], int count, double dst4[]) const {
852 static const Map2Procd gProc[] = {
853 map2_id, map2_td, map2_sd, map2_sd, map2_ad, map2_ad, map2_ad, map2_ad
854 };
skia.committer@gmail.com0264fb42012-12-06 02:01:25 +0000855
reed@google.com99b5c7f2012-12-05 22:13:59 +0000856 TypeMask mask = this->getType();
857 Map2Procd proc = (mask & kPerspective_Mask) ? map2_pd : gProc[mask];
858 proc(fMat, src2, count, dst4);
859}
860
reed@google.com8260a892011-06-13 14:02:52 +0000861///////////////////////////////////////////////////////////////////////////////
862
863void SkMatrix44::dump() const {
tomhudson@google.com9ac4a892011-06-28 13:53:13 +0000864 static const char* format =
865 "[%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 +0000866#if 0
tomhudson@google.com9ac4a892011-06-28 13:53:13 +0000867 SkDebugf(format,
reed@google.com8260a892011-06-13 14:02:52 +0000868 fMat[0][0], fMat[1][0], fMat[2][0], fMat[3][0],
869 fMat[0][1], fMat[1][1], fMat[2][1], fMat[3][1],
870 fMat[0][2], fMat[1][2], fMat[2][2], fMat[3][2],
871 fMat[0][3], fMat[1][3], fMat[2][3], fMat[3][3]);
tomhudson@google.com9ac4a892011-06-28 13:53:13 +0000872#else
873 SkDebugf(format,
874 fMat[0][0], fMat[0][1], fMat[0][2], fMat[0][3],
875 fMat[1][0], fMat[1][1], fMat[1][2], fMat[1][3],
876 fMat[2][0], fMat[2][1], fMat[2][2], fMat[2][3],
877 fMat[3][0], fMat[3][1], fMat[3][2], fMat[3][3]);
reed@google.com8260a892011-06-13 14:02:52 +0000878#endif
879}
880
881///////////////////////////////////////////////////////////////////////////////
882
reed@google.com7d683352012-12-03 21:19:52 +0000883// TODO: make this support src' perspective elements
884//
reed@google.com8260a892011-06-13 14:02:52 +0000885static void initFromMatrix(SkMScalar dst[4][4], const SkMatrix& src) {
886 sk_bzero(dst, 16 * sizeof(SkMScalar));
bsalomon@google.com72e49b82011-10-27 21:47:03 +0000887 dst[0][0] = SkScalarToMScalar(src[SkMatrix::kMScaleX]);
888 dst[1][0] = SkScalarToMScalar(src[SkMatrix::kMSkewX]);
889 dst[3][0] = SkScalarToMScalar(src[SkMatrix::kMTransX]);
890 dst[0][1] = SkScalarToMScalar(src[SkMatrix::kMSkewY]);
891 dst[1][1] = SkScalarToMScalar(src[SkMatrix::kMScaleY]);
892 dst[3][1] = SkScalarToMScalar(src[SkMatrix::kMTransY]);
reed@google.com8260a892011-06-13 14:02:52 +0000893 dst[2][2] = dst[3][3] = 1;
894}
895
896SkMatrix44::SkMatrix44(const SkMatrix& src) {
897 initFromMatrix(fMat, src);
898}
899
900SkMatrix44& SkMatrix44::operator=(const SkMatrix& src) {
901 initFromMatrix(fMat, src);
reed@google.com7d683352012-12-03 21:19:52 +0000902
903 if (src.isIdentity()) {
904 this->setTypeMask(kIdentity_Mask);
905 } else {
906 this->dirtyTypeMask();
907 }
reed@google.com8260a892011-06-13 14:02:52 +0000908 return *this;
909}
910
reed@google.com7d683352012-12-03 21:19:52 +0000911// TODO: make this support our perspective elements
912//
reed@google.com8260a892011-06-13 14:02:52 +0000913SkMatrix44::operator SkMatrix() const {
914 SkMatrix dst;
915 dst.reset(); // setup our perspective correctly for identity
916
bsalomon@google.com72e49b82011-10-27 21:47:03 +0000917 dst[SkMatrix::kMScaleX] = SkMScalarToScalar(fMat[0][0]);
918 dst[SkMatrix::kMSkewX] = SkMScalarToScalar(fMat[1][0]);
919 dst[SkMatrix::kMTransX] = SkMScalarToScalar(fMat[3][0]);
reed@google.com8260a892011-06-13 14:02:52 +0000920
bsalomon@google.com72e49b82011-10-27 21:47:03 +0000921 dst[SkMatrix::kMSkewY] = SkMScalarToScalar(fMat[0][1]);
922 dst[SkMatrix::kMScaleY] = SkMScalarToScalar(fMat[1][1]);
923 dst[SkMatrix::kMTransY] = SkMScalarToScalar(fMat[3][1]);
reed@google.com8260a892011-06-13 14:02:52 +0000924
925 return dst;
926}