blob: 9ceecbdf2a95935b3a9535188dd3937115a8f574 [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
485 inverse->fMat[3][0] = -fMat[3][0] / fMat[0][0];
486 inverse->fMat[3][1] = -fMat[3][1] / fMat[1][1];
487 inverse->fMat[3][2] = -fMat[3][2] / fMat[2][2];
488
489 inverse->fMat[0][0] = 1 / fMat[0][0];
490 inverse->fMat[1][1] = 1 / fMat[1][1];
491 inverse->fMat[2][2] = 1 / fMat[2][2];
492 inverse->fMat[3][3] = 1;
493
mike@reedtribe.orgf8b1ebc2012-12-10 03:27:47 +0000494 inverse->setTypeMask(this->getType());
reed@google.com99b5c7f2012-12-05 22:13:59 +0000495 }
496 return true;
497 }
498
tomhudson@google.com9973a8a2012-12-13 09:55:42 +0000499 double a00 = fMat[0][0];
500 double a01 = fMat[0][1];
501 double a02 = fMat[0][2];
502 double a03 = fMat[0][3];
503 double a10 = fMat[1][0];
504 double a11 = fMat[1][1];
505 double a12 = fMat[1][2];
506 double a13 = fMat[1][3];
507 double a20 = fMat[2][0];
508 double a21 = fMat[2][1];
509 double a22 = fMat[2][2];
510 double a23 = fMat[2][3];
511 double a30 = fMat[3][0];
512 double a31 = fMat[3][1];
513 double a32 = fMat[3][2];
514 double a33 = fMat[3][3];
515
516 double b00 = a00 * a11 - a01 * a10;
517 double b01 = a00 * a12 - a02 * a10;
518 double b02 = a00 * a13 - a03 * a10;
519 double b03 = a01 * a12 - a02 * a11;
520 double b04 = a01 * a13 - a03 * a11;
521 double b05 = a02 * a13 - a03 * a12;
522 double b06 = a20 * a31 - a21 * a30;
523 double b07 = a20 * a32 - a22 * a30;
524 double b08 = a20 * a33 - a23 * a30;
525 double b09 = a21 * a32 - a22 * a31;
526 double b10 = a21 * a33 - a23 * a31;
527 double b11 = a22 * a33 - a23 * a32;
528
529 // Calculate the determinant
530 double det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
531
commit-bot@chromium.orgf02f0782013-08-20 15:25:04 +0000532 double invdet = 1.0 / det;
533 // If det is zero, we want to return false. However, we also want to return false
534 // if 1/det overflows to infinity (i.e. det is denormalized). Both of these are
535 // handled by checking that 1/det is finite.
536 if (!sk_float_isfinite(invdet)) {
reed@google.com8260a892011-06-13 14:02:52 +0000537 return false;
538 }
539 if (NULL == inverse) {
540 return true;
541 }
542
tomhudson@google.com9973a8a2012-12-13 09:55:42 +0000543 b00 *= invdet;
544 b01 *= invdet;
545 b02 *= invdet;
546 b03 *= invdet;
547 b04 *= invdet;
548 b05 *= invdet;
549 b06 *= invdet;
550 b07 *= invdet;
551 b08 *= invdet;
552 b09 *= invdet;
553 b10 *= invdet;
554 b11 *= invdet;
reed@google.com8260a892011-06-13 14:02:52 +0000555
tomhudson@google.com9973a8a2012-12-13 09:55:42 +0000556 inverse->fMat[0][0] = SkDoubleToMScalar(a11 * b11 - a12 * b10 + a13 * b09);
557 inverse->fMat[0][1] = SkDoubleToMScalar(a02 * b10 - a01 * b11 - a03 * b09);
558 inverse->fMat[0][2] = SkDoubleToMScalar(a31 * b05 - a32 * b04 + a33 * b03);
559 inverse->fMat[0][3] = SkDoubleToMScalar(a22 * b04 - a21 * b05 - a23 * b03);
560 inverse->fMat[1][0] = SkDoubleToMScalar(a12 * b08 - a10 * b11 - a13 * b07);
561 inverse->fMat[1][1] = SkDoubleToMScalar(a00 * b11 - a02 * b08 + a03 * b07);
562 inverse->fMat[1][2] = SkDoubleToMScalar(a32 * b02 - a30 * b05 - a33 * b01);
563 inverse->fMat[1][3] = SkDoubleToMScalar(a20 * b05 - a22 * b02 + a23 * b01);
564 inverse->fMat[2][0] = SkDoubleToMScalar(a10 * b10 - a11 * b08 + a13 * b06);
565 inverse->fMat[2][1] = SkDoubleToMScalar(a01 * b08 - a00 * b10 - a03 * b06);
566 inverse->fMat[2][2] = SkDoubleToMScalar(a30 * b04 - a31 * b02 + a33 * b00);
567 inverse->fMat[2][3] = SkDoubleToMScalar(a21 * b02 - a20 * b04 - a23 * b00);
568 inverse->fMat[3][0] = SkDoubleToMScalar(a11 * b07 - a10 * b09 - a12 * b06);
569 inverse->fMat[3][1] = SkDoubleToMScalar(a00 * b09 - a01 * b07 + a02 * b06);
570 inverse->fMat[3][2] = SkDoubleToMScalar(a31 * b01 - a30 * b03 - a32 * b00);
571 inverse->fMat[3][3] = SkDoubleToMScalar(a20 * b03 - a21 * b01 + a22 * b00);
572 inverse->dirtyTypeMask();
reed@google.com8260a892011-06-13 14:02:52 +0000573
reed@google.com8260a892011-06-13 14:02:52 +0000574 return true;
575}
576
577///////////////////////////////////////////////////////////////////////////////
578
vollick@chromium.org9b21c252012-11-14 21:33:55 +0000579void SkMatrix44::transpose() {
580 SkTSwap(fMat[0][1], fMat[1][0]);
581 SkTSwap(fMat[0][2], fMat[2][0]);
582 SkTSwap(fMat[0][3], fMat[3][0]);
583 SkTSwap(fMat[1][2], fMat[2][1]);
584 SkTSwap(fMat[1][3], fMat[3][1]);
585 SkTSwap(fMat[2][3], fMat[3][2]);
reed@google.com7d683352012-12-03 21:19:52 +0000586
587 if (!this->isTriviallyIdentity()) {
588 this->dirtyTypeMask();
589 }
vollick@chromium.org9b21c252012-11-14 21:33:55 +0000590}
591
592///////////////////////////////////////////////////////////////////////////////
593
reed@google.com1ea95be2012-11-09 21:39:48 +0000594void SkMatrix44::mapScalars(const SkScalar src[4], SkScalar dst[4]) const {
reed@google.com7d683352012-12-03 21:19:52 +0000595 SkScalar storage[4];
596 SkScalar* result = (src == dst) ? storage : dst;
597
reed@google.com8260a892011-06-13 14:02:52 +0000598 for (int i = 0; i < 4; i++) {
599 SkMScalar value = 0;
600 for (int j = 0; j < 4; j++) {
601 value += fMat[j][i] * src[j];
602 }
bsalomon@google.com72e49b82011-10-27 21:47:03 +0000603 result[i] = SkMScalarToScalar(value);
reed@google.com8260a892011-06-13 14:02:52 +0000604 }
skia.committer@gmail.com0264fb42012-12-06 02:01:25 +0000605
reed@google.com7d683352012-12-03 21:19:52 +0000606 if (storage == result) {
607 memcpy(dst, storage, sizeof(storage));
608 }
reed@google.com8260a892011-06-13 14:02:52 +0000609}
610
reed@google.com1ea95be2012-11-09 21:39:48 +0000611#ifdef SK_MSCALAR_IS_DOUBLE
reed@google.com7d683352012-12-03 21:19:52 +0000612
reed@google.com1ea95be2012-11-09 21:39:48 +0000613void SkMatrix44::mapMScalars(const SkMScalar src[4], SkMScalar dst[4]) const {
reed@google.com7d683352012-12-03 21:19:52 +0000614 SkMScalar storage[4];
615 SkMScalar* result = (src == dst) ? storage : dst;
skia.committer@gmail.com0264fb42012-12-06 02:01:25 +0000616
reed@google.com1ea95be2012-11-09 21:39:48 +0000617 for (int i = 0; i < 4; i++) {
618 SkMScalar value = 0;
619 for (int j = 0; j < 4; j++) {
620 value += fMat[j][i] * src[j];
621 }
reed@google.com7d683352012-12-03 21:19:52 +0000622 result[i] = value;
reed@google.com1ea95be2012-11-09 21:39:48 +0000623 }
skia.committer@gmail.com0264fb42012-12-06 02:01:25 +0000624
reed@google.com7d683352012-12-03 21:19:52 +0000625 if (storage == result) {
626 memcpy(dst, storage, sizeof(storage));
627 }
reed@google.com1ea95be2012-11-09 21:39:48 +0000628}
reed@google.com7d683352012-12-03 21:19:52 +0000629
reed@google.com1ea95be2012-11-09 21:39:48 +0000630#endif
631
reed@google.com99b5c7f2012-12-05 22:13:59 +0000632typedef void (*Map2Procf)(const SkMScalar mat[][4], const float src2[], int count, float dst4[]);
633typedef void (*Map2Procd)(const SkMScalar mat[][4], const double src2[], int count, double dst4[]);
634
635static void map2_if(const SkMScalar mat[][4], const float* SK_RESTRICT src2,
636 int count, float* SK_RESTRICT dst4) {
637 for (int i = 0; i < count; ++i) {
638 dst4[0] = src2[0];
639 dst4[1] = src2[1];
640 dst4[2] = 0;
641 dst4[3] = 1;
642 src2 += 2;
643 dst4 += 4;
644 }
645}
646
647static void map2_id(const SkMScalar mat[][4], const double* SK_RESTRICT src2,
648 int count, double* SK_RESTRICT dst4) {
649 for (int i = 0; i < count; ++i) {
650 dst4[0] = src2[0];
651 dst4[1] = src2[1];
652 dst4[2] = 0;
653 dst4[3] = 1;
654 src2 += 2;
655 dst4 += 4;
656 }
657}
658
659static void map2_tf(const SkMScalar mat[][4], const float* SK_RESTRICT src2,
660 int count, float* SK_RESTRICT dst4) {
661 const float mat30 = SkMScalarToFloat(mat[3][0]);
662 const float mat31 = SkMScalarToFloat(mat[3][1]);
663 const float mat32 = SkMScalarToFloat(mat[3][2]);
664 for (int n = 0; n < count; ++n) {
665 dst4[0] = src2[0] + mat30;
666 dst4[1] = src2[1] + mat31;
667 dst4[2] = mat32;
668 dst4[3] = 1;
669 src2 += 2;
670 dst4 += 4;
671 }
672}
673
674static void map2_td(const SkMScalar mat[][4], const double* SK_RESTRICT src2,
675 int count, double* SK_RESTRICT dst4) {
676 for (int n = 0; n < count; ++n) {
677 dst4[0] = src2[0] + mat[3][0];
678 dst4[1] = src2[1] + mat[3][1];
679 dst4[2] = mat[3][2];
680 dst4[3] = 1;
681 src2 += 2;
682 dst4 += 4;
683 }
684}
685
686static void map2_sf(const SkMScalar mat[][4], const float* SK_RESTRICT src2,
687 int count, float* SK_RESTRICT dst4) {
688 const float mat32 = SkMScalarToFloat(mat[3][2]);
689 for (int n = 0; n < count; ++n) {
690 dst4[0] = SkMScalarToFloat(mat[0][0] * src2[0] + mat[3][0]);
691 dst4[1] = SkMScalarToFloat(mat[1][1] * src2[1] + mat[3][1]);
692 dst4[2] = mat32;
693 dst4[3] = 1;
694 src2 += 2;
695 dst4 += 4;
696 }
697}
698
699static void map2_sd(const SkMScalar mat[][4], const double* SK_RESTRICT src2,
700 int count, double* SK_RESTRICT dst4) {
701 for (int n = 0; n < count; ++n) {
702 dst4[0] = mat[0][0] * src2[0] + mat[3][0];
703 dst4[1] = mat[1][1] * src2[1] + mat[3][1];
704 dst4[2] = mat[3][2];
705 dst4[3] = 1;
706 src2 += 2;
707 dst4 += 4;
708 }
709}
710
711static void map2_af(const SkMScalar mat[][4], const float* SK_RESTRICT src2,
712 int count, float* SK_RESTRICT dst4) {
713 double r;
714 for (int n = 0; n < count; ++n) {
715 double sx = src2[0];
716 double sy = src2[1];
717 r = mat[0][0] * sx + mat[1][0] * sy + mat[3][0];
718 dst4[0] = SkMScalarToFloat(r);
719 r = mat[0][1] * sx + mat[1][1] * sy + mat[3][1];
720 dst4[1] = SkMScalarToFloat(r);
721 r = mat[0][2] * sx + mat[1][2] * sy + mat[3][2];
722 dst4[2] = SkMScalarToFloat(r);
723 dst4[3] = 1;
724 src2 += 2;
725 dst4 += 4;
726 }
727}
728
729static void map2_ad(const SkMScalar mat[][4], const double* SK_RESTRICT src2,
730 int count, double* SK_RESTRICT dst4) {
731 for (int n = 0; n < count; ++n) {
732 double sx = src2[0];
733 double sy = src2[1];
734 dst4[0] = mat[0][0] * sx + mat[1][0] * sy + mat[3][0];
735 dst4[1] = mat[0][1] * sx + mat[1][1] * sy + mat[3][1];
736 dst4[2] = mat[0][2] * sx + mat[1][2] * sy + mat[3][2];
737 dst4[3] = 1;
738 src2 += 2;
739 dst4 += 4;
740 }
741}
742
743static void map2_pf(const SkMScalar mat[][4], const float* SK_RESTRICT src2,
744 int count, float* SK_RESTRICT dst4) {
745 double r;
746 for (int n = 0; n < count; ++n) {
747 double sx = src2[0];
748 double sy = src2[1];
749 for (int i = 0; i < 4; i++) {
750 r = mat[0][i] * sx + mat[1][i] * sy + mat[3][i];
751 dst4[i] = SkMScalarToFloat(r);
752 }
753 src2 += 2;
754 dst4 += 4;
755 }
756}
757
758static void map2_pd(const SkMScalar mat[][4], const double* SK_RESTRICT src2,
759 int count, double* SK_RESTRICT dst4) {
760 for (int n = 0; n < count; ++n) {
761 double sx = src2[0];
762 double sy = src2[1];
763 for (int i = 0; i < 4; i++) {
764 dst4[i] = mat[0][i] * sx + mat[1][i] * sy + mat[3][i];
765 }
766 src2 += 2;
767 dst4 += 4;
768 }
769}
770
771void SkMatrix44::map2(const float src2[], int count, float dst4[]) const {
772 static const Map2Procf gProc[] = {
773 map2_if, map2_tf, map2_sf, map2_sf, map2_af, map2_af, map2_af, map2_af
774 };
775
776 TypeMask mask = this->getType();
777 Map2Procf proc = (mask & kPerspective_Mask) ? map2_pf : gProc[mask];
778 proc(fMat, src2, count, dst4);
779}
780
781void SkMatrix44::map2(const double src2[], int count, double dst4[]) const {
782 static const Map2Procd gProc[] = {
783 map2_id, map2_td, map2_sd, map2_sd, map2_ad, map2_ad, map2_ad, map2_ad
784 };
skia.committer@gmail.com0264fb42012-12-06 02:01:25 +0000785
reed@google.com99b5c7f2012-12-05 22:13:59 +0000786 TypeMask mask = this->getType();
787 Map2Procd proc = (mask & kPerspective_Mask) ? map2_pd : gProc[mask];
788 proc(fMat, src2, count, dst4);
789}
790
reed@google.com8260a892011-06-13 14:02:52 +0000791///////////////////////////////////////////////////////////////////////////////
792
793void SkMatrix44::dump() const {
tomhudson@google.com9ac4a892011-06-28 13:53:13 +0000794 static const char* format =
795 "[%g %g %g %g][%g %g %g %g][%g %g %g %g][%g %g %g %g]\n";
reed@google.com8260a892011-06-13 14:02:52 +0000796#if 0
tomhudson@google.com9ac4a892011-06-28 13:53:13 +0000797 SkDebugf(format,
reed@google.com8260a892011-06-13 14:02:52 +0000798 fMat[0][0], fMat[1][0], fMat[2][0], fMat[3][0],
799 fMat[0][1], fMat[1][1], fMat[2][1], fMat[3][1],
800 fMat[0][2], fMat[1][2], fMat[2][2], fMat[3][2],
801 fMat[0][3], fMat[1][3], fMat[2][3], fMat[3][3]);
tomhudson@google.com9ac4a892011-06-28 13:53:13 +0000802#else
803 SkDebugf(format,
804 fMat[0][0], fMat[0][1], fMat[0][2], fMat[0][3],
805 fMat[1][0], fMat[1][1], fMat[1][2], fMat[1][3],
806 fMat[2][0], fMat[2][1], fMat[2][2], fMat[2][3],
807 fMat[3][0], fMat[3][1], fMat[3][2], fMat[3][3]);
reed@google.com8260a892011-06-13 14:02:52 +0000808#endif
809}
810
811///////////////////////////////////////////////////////////////////////////////
812
reed@google.com7d683352012-12-03 21:19:52 +0000813// TODO: make this support src' perspective elements
814//
reed@google.com8260a892011-06-13 14:02:52 +0000815static void initFromMatrix(SkMScalar dst[4][4], const SkMatrix& src) {
816 sk_bzero(dst, 16 * sizeof(SkMScalar));
bsalomon@google.com72e49b82011-10-27 21:47:03 +0000817 dst[0][0] = SkScalarToMScalar(src[SkMatrix::kMScaleX]);
818 dst[1][0] = SkScalarToMScalar(src[SkMatrix::kMSkewX]);
819 dst[3][0] = SkScalarToMScalar(src[SkMatrix::kMTransX]);
820 dst[0][1] = SkScalarToMScalar(src[SkMatrix::kMSkewY]);
821 dst[1][1] = SkScalarToMScalar(src[SkMatrix::kMScaleY]);
822 dst[3][1] = SkScalarToMScalar(src[SkMatrix::kMTransY]);
reed@google.com8260a892011-06-13 14:02:52 +0000823 dst[2][2] = dst[3][3] = 1;
824}
825
826SkMatrix44::SkMatrix44(const SkMatrix& src) {
827 initFromMatrix(fMat, src);
828}
829
830SkMatrix44& SkMatrix44::operator=(const SkMatrix& src) {
831 initFromMatrix(fMat, src);
reed@google.com7d683352012-12-03 21:19:52 +0000832
833 if (src.isIdentity()) {
834 this->setTypeMask(kIdentity_Mask);
835 } else {
836 this->dirtyTypeMask();
837 }
reed@google.com8260a892011-06-13 14:02:52 +0000838 return *this;
839}
840
reed@google.com7d683352012-12-03 21:19:52 +0000841// TODO: make this support our perspective elements
842//
reed@google.com8260a892011-06-13 14:02:52 +0000843SkMatrix44::operator SkMatrix() const {
844 SkMatrix dst;
845 dst.reset(); // setup our perspective correctly for identity
846
bsalomon@google.com72e49b82011-10-27 21:47:03 +0000847 dst[SkMatrix::kMScaleX] = SkMScalarToScalar(fMat[0][0]);
848 dst[SkMatrix::kMSkewX] = SkMScalarToScalar(fMat[1][0]);
849 dst[SkMatrix::kMTransX] = SkMScalarToScalar(fMat[3][0]);
reed@google.com8260a892011-06-13 14:02:52 +0000850
bsalomon@google.com72e49b82011-10-27 21:47:03 +0000851 dst[SkMatrix::kMSkewY] = SkMScalarToScalar(fMat[0][1]);
852 dst[SkMatrix::kMScaleY] = SkMScalarToScalar(fMat[1][1]);
853 dst[SkMatrix::kMTransY] = SkMScalarToScalar(fMat[3][1]);
reed@google.com8260a892011-06-13 14:02:52 +0000854
855 return dst;
856}