blob: 92c8715faaec94972770f8db05b372c1245366a8 [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
reed@google.com8260a892011-06-13 14:02:52 +0000532 if (dabs(det) < TOO_SMALL_FOR_DETERMINANT) {
533 return false;
534 }
535 if (NULL == inverse) {
536 return true;
537 }
tomhudson@google.com9973a8a2012-12-13 09:55:42 +0000538 double invdet = 1.0 / det;
reed@google.com8260a892011-06-13 14:02:52 +0000539
tomhudson@google.com9973a8a2012-12-13 09:55:42 +0000540 b00 *= invdet;
541 b01 *= invdet;
542 b02 *= invdet;
543 b03 *= invdet;
544 b04 *= invdet;
545 b05 *= invdet;
546 b06 *= invdet;
547 b07 *= invdet;
548 b08 *= invdet;
549 b09 *= invdet;
550 b10 *= invdet;
551 b11 *= invdet;
reed@google.com8260a892011-06-13 14:02:52 +0000552
tomhudson@google.com9973a8a2012-12-13 09:55:42 +0000553 inverse->fMat[0][0] = SkDoubleToMScalar(a11 * b11 - a12 * b10 + a13 * b09);
554 inverse->fMat[0][1] = SkDoubleToMScalar(a02 * b10 - a01 * b11 - a03 * b09);
555 inverse->fMat[0][2] = SkDoubleToMScalar(a31 * b05 - a32 * b04 + a33 * b03);
556 inverse->fMat[0][3] = SkDoubleToMScalar(a22 * b04 - a21 * b05 - a23 * b03);
557 inverse->fMat[1][0] = SkDoubleToMScalar(a12 * b08 - a10 * b11 - a13 * b07);
558 inverse->fMat[1][1] = SkDoubleToMScalar(a00 * b11 - a02 * b08 + a03 * b07);
559 inverse->fMat[1][2] = SkDoubleToMScalar(a32 * b02 - a30 * b05 - a33 * b01);
560 inverse->fMat[1][3] = SkDoubleToMScalar(a20 * b05 - a22 * b02 + a23 * b01);
561 inverse->fMat[2][0] = SkDoubleToMScalar(a10 * b10 - a11 * b08 + a13 * b06);
562 inverse->fMat[2][1] = SkDoubleToMScalar(a01 * b08 - a00 * b10 - a03 * b06);
563 inverse->fMat[2][2] = SkDoubleToMScalar(a30 * b04 - a31 * b02 + a33 * b00);
564 inverse->fMat[2][3] = SkDoubleToMScalar(a21 * b02 - a20 * b04 - a23 * b00);
565 inverse->fMat[3][0] = SkDoubleToMScalar(a11 * b07 - a10 * b09 - a12 * b06);
566 inverse->fMat[3][1] = SkDoubleToMScalar(a00 * b09 - a01 * b07 + a02 * b06);
567 inverse->fMat[3][2] = SkDoubleToMScalar(a31 * b01 - a30 * b03 - a32 * b00);
568 inverse->fMat[3][3] = SkDoubleToMScalar(a20 * b03 - a21 * b01 + a22 * b00);
569 inverse->dirtyTypeMask();
reed@google.com8260a892011-06-13 14:02:52 +0000570
reed@google.com7d683352012-12-03 21:19:52 +0000571 inverse->dirtyTypeMask();
reed@google.com8260a892011-06-13 14:02:52 +0000572 return true;
573}
574
575///////////////////////////////////////////////////////////////////////////////
576
vollick@chromium.org9b21c252012-11-14 21:33:55 +0000577void SkMatrix44::transpose() {
578 SkTSwap(fMat[0][1], fMat[1][0]);
579 SkTSwap(fMat[0][2], fMat[2][0]);
580 SkTSwap(fMat[0][3], fMat[3][0]);
581 SkTSwap(fMat[1][2], fMat[2][1]);
582 SkTSwap(fMat[1][3], fMat[3][1]);
583 SkTSwap(fMat[2][3], fMat[3][2]);
reed@google.com7d683352012-12-03 21:19:52 +0000584
585 if (!this->isTriviallyIdentity()) {
586 this->dirtyTypeMask();
587 }
vollick@chromium.org9b21c252012-11-14 21:33:55 +0000588}
589
590///////////////////////////////////////////////////////////////////////////////
591
reed@google.com1ea95be2012-11-09 21:39:48 +0000592void SkMatrix44::mapScalars(const SkScalar src[4], SkScalar dst[4]) const {
reed@google.com7d683352012-12-03 21:19:52 +0000593 SkScalar storage[4];
594 SkScalar* result = (src == dst) ? storage : dst;
595
reed@google.com8260a892011-06-13 14:02:52 +0000596 for (int i = 0; i < 4; i++) {
597 SkMScalar value = 0;
598 for (int j = 0; j < 4; j++) {
599 value += fMat[j][i] * src[j];
600 }
bsalomon@google.com72e49b82011-10-27 21:47:03 +0000601 result[i] = SkMScalarToScalar(value);
reed@google.com8260a892011-06-13 14:02:52 +0000602 }
skia.committer@gmail.com0264fb42012-12-06 02:01:25 +0000603
reed@google.com7d683352012-12-03 21:19:52 +0000604 if (storage == result) {
605 memcpy(dst, storage, sizeof(storage));
606 }
reed@google.com8260a892011-06-13 14:02:52 +0000607}
608
reed@google.com1ea95be2012-11-09 21:39:48 +0000609#ifdef SK_MSCALAR_IS_DOUBLE
reed@google.com7d683352012-12-03 21:19:52 +0000610
reed@google.com1ea95be2012-11-09 21:39:48 +0000611void SkMatrix44::mapMScalars(const SkMScalar src[4], SkMScalar dst[4]) const {
reed@google.com7d683352012-12-03 21:19:52 +0000612 SkMScalar storage[4];
613 SkMScalar* result = (src == dst) ? storage : dst;
skia.committer@gmail.com0264fb42012-12-06 02:01:25 +0000614
reed@google.com1ea95be2012-11-09 21:39:48 +0000615 for (int i = 0; i < 4; i++) {
616 SkMScalar value = 0;
617 for (int j = 0; j < 4; j++) {
618 value += fMat[j][i] * src[j];
619 }
reed@google.com7d683352012-12-03 21:19:52 +0000620 result[i] = value;
reed@google.com1ea95be2012-11-09 21:39:48 +0000621 }
skia.committer@gmail.com0264fb42012-12-06 02:01:25 +0000622
reed@google.com7d683352012-12-03 21:19:52 +0000623 if (storage == result) {
624 memcpy(dst, storage, sizeof(storage));
625 }
reed@google.com1ea95be2012-11-09 21:39:48 +0000626}
reed@google.com7d683352012-12-03 21:19:52 +0000627
reed@google.com1ea95be2012-11-09 21:39:48 +0000628#endif
629
reed@google.com99b5c7f2012-12-05 22:13:59 +0000630typedef void (*Map2Procf)(const SkMScalar mat[][4], const float src2[], int count, float dst4[]);
631typedef void (*Map2Procd)(const SkMScalar mat[][4], const double src2[], int count, double dst4[]);
632
633static void map2_if(const SkMScalar mat[][4], const float* SK_RESTRICT src2,
634 int count, float* SK_RESTRICT dst4) {
635 for (int i = 0; i < count; ++i) {
636 dst4[0] = src2[0];
637 dst4[1] = src2[1];
638 dst4[2] = 0;
639 dst4[3] = 1;
640 src2 += 2;
641 dst4 += 4;
642 }
643}
644
645static void map2_id(const SkMScalar mat[][4], const double* SK_RESTRICT src2,
646 int count, double* SK_RESTRICT dst4) {
647 for (int i = 0; i < count; ++i) {
648 dst4[0] = src2[0];
649 dst4[1] = src2[1];
650 dst4[2] = 0;
651 dst4[3] = 1;
652 src2 += 2;
653 dst4 += 4;
654 }
655}
656
657static void map2_tf(const SkMScalar mat[][4], const float* SK_RESTRICT src2,
658 int count, float* SK_RESTRICT dst4) {
659 const float mat30 = SkMScalarToFloat(mat[3][0]);
660 const float mat31 = SkMScalarToFloat(mat[3][1]);
661 const float mat32 = SkMScalarToFloat(mat[3][2]);
662 for (int n = 0; n < count; ++n) {
663 dst4[0] = src2[0] + mat30;
664 dst4[1] = src2[1] + mat31;
665 dst4[2] = mat32;
666 dst4[3] = 1;
667 src2 += 2;
668 dst4 += 4;
669 }
670}
671
672static void map2_td(const SkMScalar mat[][4], const double* SK_RESTRICT src2,
673 int count, double* SK_RESTRICT dst4) {
674 for (int n = 0; n < count; ++n) {
675 dst4[0] = src2[0] + mat[3][0];
676 dst4[1] = src2[1] + mat[3][1];
677 dst4[2] = mat[3][2];
678 dst4[3] = 1;
679 src2 += 2;
680 dst4 += 4;
681 }
682}
683
684static void map2_sf(const SkMScalar mat[][4], const float* SK_RESTRICT src2,
685 int count, float* SK_RESTRICT dst4) {
686 const float mat32 = SkMScalarToFloat(mat[3][2]);
687 for (int n = 0; n < count; ++n) {
688 dst4[0] = SkMScalarToFloat(mat[0][0] * src2[0] + mat[3][0]);
689 dst4[1] = SkMScalarToFloat(mat[1][1] * src2[1] + mat[3][1]);
690 dst4[2] = mat32;
691 dst4[3] = 1;
692 src2 += 2;
693 dst4 += 4;
694 }
695}
696
697static void map2_sd(const SkMScalar mat[][4], const double* SK_RESTRICT src2,
698 int count, double* SK_RESTRICT dst4) {
699 for (int n = 0; n < count; ++n) {
700 dst4[0] = mat[0][0] * src2[0] + mat[3][0];
701 dst4[1] = mat[1][1] * src2[1] + mat[3][1];
702 dst4[2] = mat[3][2];
703 dst4[3] = 1;
704 src2 += 2;
705 dst4 += 4;
706 }
707}
708
709static void map2_af(const SkMScalar mat[][4], const float* SK_RESTRICT src2,
710 int count, float* SK_RESTRICT dst4) {
711 double r;
712 for (int n = 0; n < count; ++n) {
713 double sx = src2[0];
714 double sy = src2[1];
715 r = mat[0][0] * sx + mat[1][0] * sy + mat[3][0];
716 dst4[0] = SkMScalarToFloat(r);
717 r = mat[0][1] * sx + mat[1][1] * sy + mat[3][1];
718 dst4[1] = SkMScalarToFloat(r);
719 r = mat[0][2] * sx + mat[1][2] * sy + mat[3][2];
720 dst4[2] = SkMScalarToFloat(r);
721 dst4[3] = 1;
722 src2 += 2;
723 dst4 += 4;
724 }
725}
726
727static void map2_ad(const SkMScalar mat[][4], const double* SK_RESTRICT src2,
728 int count, double* SK_RESTRICT dst4) {
729 for (int n = 0; n < count; ++n) {
730 double sx = src2[0];
731 double sy = src2[1];
732 dst4[0] = mat[0][0] * sx + mat[1][0] * sy + mat[3][0];
733 dst4[1] = mat[0][1] * sx + mat[1][1] * sy + mat[3][1];
734 dst4[2] = mat[0][2] * sx + mat[1][2] * sy + mat[3][2];
735 dst4[3] = 1;
736 src2 += 2;
737 dst4 += 4;
738 }
739}
740
741static void map2_pf(const SkMScalar mat[][4], const float* SK_RESTRICT src2,
742 int count, float* SK_RESTRICT dst4) {
743 double r;
744 for (int n = 0; n < count; ++n) {
745 double sx = src2[0];
746 double sy = src2[1];
747 for (int i = 0; i < 4; i++) {
748 r = mat[0][i] * sx + mat[1][i] * sy + mat[3][i];
749 dst4[i] = SkMScalarToFloat(r);
750 }
751 src2 += 2;
752 dst4 += 4;
753 }
754}
755
756static void map2_pd(const SkMScalar mat[][4], const double* SK_RESTRICT src2,
757 int count, double* SK_RESTRICT dst4) {
758 for (int n = 0; n < count; ++n) {
759 double sx = src2[0];
760 double sy = src2[1];
761 for (int i = 0; i < 4; i++) {
762 dst4[i] = mat[0][i] * sx + mat[1][i] * sy + mat[3][i];
763 }
764 src2 += 2;
765 dst4 += 4;
766 }
767}
768
769void SkMatrix44::map2(const float src2[], int count, float dst4[]) const {
770 static const Map2Procf gProc[] = {
771 map2_if, map2_tf, map2_sf, map2_sf, map2_af, map2_af, map2_af, map2_af
772 };
773
774 TypeMask mask = this->getType();
775 Map2Procf proc = (mask & kPerspective_Mask) ? map2_pf : gProc[mask];
776 proc(fMat, src2, count, dst4);
777}
778
779void SkMatrix44::map2(const double src2[], int count, double dst4[]) const {
780 static const Map2Procd gProc[] = {
781 map2_id, map2_td, map2_sd, map2_sd, map2_ad, map2_ad, map2_ad, map2_ad
782 };
skia.committer@gmail.com0264fb42012-12-06 02:01:25 +0000783
reed@google.com99b5c7f2012-12-05 22:13:59 +0000784 TypeMask mask = this->getType();
785 Map2Procd proc = (mask & kPerspective_Mask) ? map2_pd : gProc[mask];
786 proc(fMat, src2, count, dst4);
787}
788
reed@google.com8260a892011-06-13 14:02:52 +0000789///////////////////////////////////////////////////////////////////////////////
790
791void SkMatrix44::dump() const {
tomhudson@google.com9ac4a892011-06-28 13:53:13 +0000792 static const char* format =
793 "[%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 +0000794#if 0
tomhudson@google.com9ac4a892011-06-28 13:53:13 +0000795 SkDebugf(format,
reed@google.com8260a892011-06-13 14:02:52 +0000796 fMat[0][0], fMat[1][0], fMat[2][0], fMat[3][0],
797 fMat[0][1], fMat[1][1], fMat[2][1], fMat[3][1],
798 fMat[0][2], fMat[1][2], fMat[2][2], fMat[3][2],
799 fMat[0][3], fMat[1][3], fMat[2][3], fMat[3][3]);
tomhudson@google.com9ac4a892011-06-28 13:53:13 +0000800#else
801 SkDebugf(format,
802 fMat[0][0], fMat[0][1], fMat[0][2], fMat[0][3],
803 fMat[1][0], fMat[1][1], fMat[1][2], fMat[1][3],
804 fMat[2][0], fMat[2][1], fMat[2][2], fMat[2][3],
805 fMat[3][0], fMat[3][1], fMat[3][2], fMat[3][3]);
reed@google.com8260a892011-06-13 14:02:52 +0000806#endif
807}
808
809///////////////////////////////////////////////////////////////////////////////
810
reed@google.com7d683352012-12-03 21:19:52 +0000811// TODO: make this support src' perspective elements
812//
reed@google.com8260a892011-06-13 14:02:52 +0000813static void initFromMatrix(SkMScalar dst[4][4], const SkMatrix& src) {
814 sk_bzero(dst, 16 * sizeof(SkMScalar));
bsalomon@google.com72e49b82011-10-27 21:47:03 +0000815 dst[0][0] = SkScalarToMScalar(src[SkMatrix::kMScaleX]);
816 dst[1][0] = SkScalarToMScalar(src[SkMatrix::kMSkewX]);
817 dst[3][0] = SkScalarToMScalar(src[SkMatrix::kMTransX]);
818 dst[0][1] = SkScalarToMScalar(src[SkMatrix::kMSkewY]);
819 dst[1][1] = SkScalarToMScalar(src[SkMatrix::kMScaleY]);
820 dst[3][1] = SkScalarToMScalar(src[SkMatrix::kMTransY]);
reed@google.com8260a892011-06-13 14:02:52 +0000821 dst[2][2] = dst[3][3] = 1;
822}
823
824SkMatrix44::SkMatrix44(const SkMatrix& src) {
825 initFromMatrix(fMat, src);
826}
827
828SkMatrix44& SkMatrix44::operator=(const SkMatrix& src) {
829 initFromMatrix(fMat, src);
reed@google.com7d683352012-12-03 21:19:52 +0000830
831 if (src.isIdentity()) {
832 this->setTypeMask(kIdentity_Mask);
833 } else {
834 this->dirtyTypeMask();
835 }
reed@google.com8260a892011-06-13 14:02:52 +0000836 return *this;
837}
838
reed@google.com7d683352012-12-03 21:19:52 +0000839// TODO: make this support our perspective elements
840//
reed@google.com8260a892011-06-13 14:02:52 +0000841SkMatrix44::operator SkMatrix() const {
842 SkMatrix dst;
843 dst.reset(); // setup our perspective correctly for identity
844
bsalomon@google.com72e49b82011-10-27 21:47:03 +0000845 dst[SkMatrix::kMScaleX] = SkMScalarToScalar(fMat[0][0]);
846 dst[SkMatrix::kMSkewX] = SkMScalarToScalar(fMat[1][0]);
847 dst[SkMatrix::kMTransX] = SkMScalarToScalar(fMat[3][0]);
reed@google.com8260a892011-06-13 14:02:52 +0000848
bsalomon@google.com72e49b82011-10-27 21:47:03 +0000849 dst[SkMatrix::kMSkewY] = SkMScalarToScalar(fMat[0][1]);
850 dst[SkMatrix::kMScaleY] = SkMScalarToScalar(fMat[1][1]);
851 dst[SkMatrix::kMTransY] = SkMScalarToScalar(fMat[3][1]);
reed@google.com8260a892011-06-13 14:02:52 +0000852
853 return dst;
854}