blob: 1906593acd8a1a5ca81d243b9bd9a0382b1d8771 [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.com99b5c7f2012-12-05 22:13:59 +0000363 if (bits_isonly(a_mask | b_mask, kScale_Mask | kTranslate_Mask)) {
tomhudson@google.com7cfb9c72013-01-17 13:29:35 +0000364 sk_bzero(result, sizeof(storage));
reed@google.com99b5c7f2012-12-05 22:13:59 +0000365 result[0] = a.fMat[0][0] * b.fMat[0][0];
366 result[5] = a.fMat[1][1] * b.fMat[1][1];
367 result[10] = a.fMat[2][2] * b.fMat[2][2];
368 result[12] = a.fMat[0][0] * b.fMat[3][0] + a.fMat[3][0];
369 result[13] = a.fMat[1][1] * b.fMat[3][1] + a.fMat[3][1];
370 result[14] = a.fMat[2][2] * b.fMat[3][2] + a.fMat[3][2];
371 result[15] = 1;
372 } else {
373 for (int j = 0; j < 4; j++) {
374 for (int i = 0; i < 4; i++) {
375 double value = 0;
376 for (int k = 0; k < 4; k++) {
377 value += SkMScalarToDouble(a.fMat[k][i]) * b.fMat[j][k];
378 }
379 *result++ = SkDoubleToMScalar(value);
reed@google.com8260a892011-06-13 14:02:52 +0000380 }
reed@google.com8260a892011-06-13 14:02:52 +0000381 }
382 }
reed@google.com99b5c7f2012-12-05 22:13:59 +0000383
reed@google.com7d683352012-12-03 21:19:52 +0000384 if (useStorage) {
tomhudson@google.com7cfb9c72013-01-17 13:29:35 +0000385 memcpy(fMat, storage, sizeof(storage));
reed@google.com7d683352012-12-03 21:19:52 +0000386 }
reed@google.com7d683352012-12-03 21:19:52 +0000387 this->dirtyTypeMask();
reed@google.com8260a892011-06-13 14:02:52 +0000388}
389
390///////////////////////////////////////////////////////////////////////////////
391
392static inline SkMScalar det2x2(double m00, double m01, double m10, double m11) {
bsalomon@google.com9d12f5c2011-09-29 18:08:18 +0000393 return SkDoubleToMScalar(m00 * m11 - m10 * m01);
reed@google.com8260a892011-06-13 14:02:52 +0000394}
395
396static inline double det3x3(double m00, double m01, double m02,
397 double m10, double m11, double m12,
398 double m20, double m21, double m22) {
399 return m00 * det2x2(m11, m12, m21, m22) -
400 m10 * det2x2(m01, m02, m21, m22) +
401 m20 * det2x2(m01, m02, m11, m12);
402}
403
404/** We always perform the calculation in doubles, to avoid prematurely losing
405 precision along the way. This relies on the compiler automatically
406 promoting our SkMScalar values to double (if needed).
407 */
408double SkMatrix44::determinant() const {
mike@reedtribe.orgf8b1ebc2012-12-10 03:27:47 +0000409 if (this->isIdentity()) {
410 return 1;
411 }
412 if (this->isScaleTranslate()) {
413 return fMat[0][0] * fMat[1][1] * fMat[2][2] * fMat[3][3];
414 }
415
tomhudson@google.com9973a8a2012-12-13 09:55:42 +0000416 double a00 = fMat[0][0];
417 double a01 = fMat[0][1];
418 double a02 = fMat[0][2];
419 double a03 = fMat[0][3];
420 double a10 = fMat[1][0];
421 double a11 = fMat[1][1];
422 double a12 = fMat[1][2];
423 double a13 = fMat[1][3];
424 double a20 = fMat[2][0];
425 double a21 = fMat[2][1];
426 double a22 = fMat[2][2];
427 double a23 = fMat[2][3];
428 double a30 = fMat[3][0];
429 double a31 = fMat[3][1];
430 double a32 = fMat[3][2];
431 double a33 = fMat[3][3];
432
433 double b00 = a00 * a11 - a01 * a10;
434 double b01 = a00 * a12 - a02 * a10;
435 double b02 = a00 * a13 - a03 * a10;
436 double b03 = a01 * a12 - a02 * a11;
437 double b04 = a01 * a13 - a03 * a11;
438 double b05 = a02 * a13 - a03 * a12;
439 double b06 = a20 * a31 - a21 * a30;
440 double b07 = a20 * a32 - a22 * a30;
441 double b08 = a20 * a33 - a23 * a30;
442 double b09 = a21 * a32 - a22 * a31;
443 double b10 = a21 * a33 - a23 * a31;
444 double b11 = a22 * a33 - a23 * a32;
445
446 // Calculate the determinant
447 return b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
reed@google.com8260a892011-06-13 14:02:52 +0000448}
449
450///////////////////////////////////////////////////////////////////////////////
451
452// just picked a small value. not sure how to pick the "right" one
453#define TOO_SMALL_FOR_DETERMINANT (1.e-8)
454
455static inline double dabs(double x) {
456 if (x < 0) {
457 x = -x;
458 }
459 return x;
460}
461
462bool SkMatrix44::invert(SkMatrix44* inverse) const {
mike@reedtribe.orgf8b1ebc2012-12-10 03:27:47 +0000463 if (this->isIdentity()) {
reed@google.com7d683352012-12-03 21:19:52 +0000464 if (inverse) {
465 *inverse = *this;
466 return true;
467 }
468 }
mike@reedtribe.orgf8b1ebc2012-12-10 03:27:47 +0000469 if (this->isTranslate()) {
reed@google.com99b5c7f2012-12-05 22:13:59 +0000470 if (inverse) {
471 inverse->setTranslate(-fMat[3][0], -fMat[3][1], -fMat[3][2]);
472 }
473 return true;
474 }
mike@reedtribe.orgf8b1ebc2012-12-10 03:27:47 +0000475 if (this->isScaleTranslate()) {
reed@google.com99b5c7f2012-12-05 22:13:59 +0000476 if (0 == fMat[0][0] * fMat[1][1] * fMat[2][2]) {
477 return false;
478 }
479 if (inverse) {
480 sk_bzero(inverse->fMat, sizeof(inverse->fMat));
481
482 inverse->fMat[3][0] = -fMat[3][0] / fMat[0][0];
483 inverse->fMat[3][1] = -fMat[3][1] / fMat[1][1];
484 inverse->fMat[3][2] = -fMat[3][2] / fMat[2][2];
485
486 inverse->fMat[0][0] = 1 / fMat[0][0];
487 inverse->fMat[1][1] = 1 / fMat[1][1];
488 inverse->fMat[2][2] = 1 / fMat[2][2];
489 inverse->fMat[3][3] = 1;
490
mike@reedtribe.orgf8b1ebc2012-12-10 03:27:47 +0000491 inverse->setTypeMask(this->getType());
reed@google.com99b5c7f2012-12-05 22:13:59 +0000492 }
493 return true;
494 }
495
tomhudson@google.com9973a8a2012-12-13 09:55:42 +0000496 double a00 = fMat[0][0];
497 double a01 = fMat[0][1];
498 double a02 = fMat[0][2];
499 double a03 = fMat[0][3];
500 double a10 = fMat[1][0];
501 double a11 = fMat[1][1];
502 double a12 = fMat[1][2];
503 double a13 = fMat[1][3];
504 double a20 = fMat[2][0];
505 double a21 = fMat[2][1];
506 double a22 = fMat[2][2];
507 double a23 = fMat[2][3];
508 double a30 = fMat[3][0];
509 double a31 = fMat[3][1];
510 double a32 = fMat[3][2];
511 double a33 = fMat[3][3];
512
513 double b00 = a00 * a11 - a01 * a10;
514 double b01 = a00 * a12 - a02 * a10;
515 double b02 = a00 * a13 - a03 * a10;
516 double b03 = a01 * a12 - a02 * a11;
517 double b04 = a01 * a13 - a03 * a11;
518 double b05 = a02 * a13 - a03 * a12;
519 double b06 = a20 * a31 - a21 * a30;
520 double b07 = a20 * a32 - a22 * a30;
521 double b08 = a20 * a33 - a23 * a30;
522 double b09 = a21 * a32 - a22 * a31;
523 double b10 = a21 * a33 - a23 * a31;
524 double b11 = a22 * a33 - a23 * a32;
525
526 // Calculate the determinant
527 double det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
528
reed@google.com8260a892011-06-13 14:02:52 +0000529 if (dabs(det) < TOO_SMALL_FOR_DETERMINANT) {
530 return false;
531 }
532 if (NULL == inverse) {
533 return true;
534 }
tomhudson@google.com9973a8a2012-12-13 09:55:42 +0000535 double invdet = 1.0 / det;
reed@google.com8260a892011-06-13 14:02:52 +0000536
tomhudson@google.com9973a8a2012-12-13 09:55:42 +0000537 b00 *= invdet;
538 b01 *= invdet;
539 b02 *= invdet;
540 b03 *= invdet;
541 b04 *= invdet;
542 b05 *= invdet;
543 b06 *= invdet;
544 b07 *= invdet;
545 b08 *= invdet;
546 b09 *= invdet;
547 b10 *= invdet;
548 b11 *= invdet;
reed@google.com8260a892011-06-13 14:02:52 +0000549
tomhudson@google.com9973a8a2012-12-13 09:55:42 +0000550 inverse->fMat[0][0] = SkDoubleToMScalar(a11 * b11 - a12 * b10 + a13 * b09);
551 inverse->fMat[0][1] = SkDoubleToMScalar(a02 * b10 - a01 * b11 - a03 * b09);
552 inverse->fMat[0][2] = SkDoubleToMScalar(a31 * b05 - a32 * b04 + a33 * b03);
553 inverse->fMat[0][3] = SkDoubleToMScalar(a22 * b04 - a21 * b05 - a23 * b03);
554 inverse->fMat[1][0] = SkDoubleToMScalar(a12 * b08 - a10 * b11 - a13 * b07);
555 inverse->fMat[1][1] = SkDoubleToMScalar(a00 * b11 - a02 * b08 + a03 * b07);
556 inverse->fMat[1][2] = SkDoubleToMScalar(a32 * b02 - a30 * b05 - a33 * b01);
557 inverse->fMat[1][3] = SkDoubleToMScalar(a20 * b05 - a22 * b02 + a23 * b01);
558 inverse->fMat[2][0] = SkDoubleToMScalar(a10 * b10 - a11 * b08 + a13 * b06);
559 inverse->fMat[2][1] = SkDoubleToMScalar(a01 * b08 - a00 * b10 - a03 * b06);
560 inverse->fMat[2][2] = SkDoubleToMScalar(a30 * b04 - a31 * b02 + a33 * b00);
561 inverse->fMat[2][3] = SkDoubleToMScalar(a21 * b02 - a20 * b04 - a23 * b00);
562 inverse->fMat[3][0] = SkDoubleToMScalar(a11 * b07 - a10 * b09 - a12 * b06);
563 inverse->fMat[3][1] = SkDoubleToMScalar(a00 * b09 - a01 * b07 + a02 * b06);
564 inverse->fMat[3][2] = SkDoubleToMScalar(a31 * b01 - a30 * b03 - a32 * b00);
565 inverse->fMat[3][3] = SkDoubleToMScalar(a20 * b03 - a21 * b01 + a22 * b00);
566 inverse->dirtyTypeMask();
reed@google.com8260a892011-06-13 14:02:52 +0000567
reed@google.com7d683352012-12-03 21:19:52 +0000568 inverse->dirtyTypeMask();
reed@google.com8260a892011-06-13 14:02:52 +0000569 return true;
570}
571
572///////////////////////////////////////////////////////////////////////////////
573
vollick@chromium.org9b21c252012-11-14 21:33:55 +0000574void SkMatrix44::transpose() {
575 SkTSwap(fMat[0][1], fMat[1][0]);
576 SkTSwap(fMat[0][2], fMat[2][0]);
577 SkTSwap(fMat[0][3], fMat[3][0]);
578 SkTSwap(fMat[1][2], fMat[2][1]);
579 SkTSwap(fMat[1][3], fMat[3][1]);
580 SkTSwap(fMat[2][3], fMat[3][2]);
reed@google.com7d683352012-12-03 21:19:52 +0000581
582 if (!this->isTriviallyIdentity()) {
583 this->dirtyTypeMask();
584 }
vollick@chromium.org9b21c252012-11-14 21:33:55 +0000585}
586
587///////////////////////////////////////////////////////////////////////////////
588
reed@google.com1ea95be2012-11-09 21:39:48 +0000589void SkMatrix44::mapScalars(const SkScalar src[4], SkScalar dst[4]) const {
reed@google.com7d683352012-12-03 21:19:52 +0000590 SkScalar storage[4];
591 SkScalar* result = (src == dst) ? storage : dst;
592
reed@google.com8260a892011-06-13 14:02:52 +0000593 for (int i = 0; i < 4; i++) {
594 SkMScalar value = 0;
595 for (int j = 0; j < 4; j++) {
596 value += fMat[j][i] * src[j];
597 }
bsalomon@google.com72e49b82011-10-27 21:47:03 +0000598 result[i] = SkMScalarToScalar(value);
reed@google.com8260a892011-06-13 14:02:52 +0000599 }
skia.committer@gmail.com0264fb42012-12-06 02:01:25 +0000600
reed@google.com7d683352012-12-03 21:19:52 +0000601 if (storage == result) {
602 memcpy(dst, storage, sizeof(storage));
603 }
reed@google.com8260a892011-06-13 14:02:52 +0000604}
605
reed@google.com1ea95be2012-11-09 21:39:48 +0000606#ifdef SK_MSCALAR_IS_DOUBLE
reed@google.com7d683352012-12-03 21:19:52 +0000607
reed@google.com1ea95be2012-11-09 21:39:48 +0000608void SkMatrix44::mapMScalars(const SkMScalar src[4], SkMScalar dst[4]) const {
reed@google.com7d683352012-12-03 21:19:52 +0000609 SkMScalar storage[4];
610 SkMScalar* result = (src == dst) ? storage : dst;
skia.committer@gmail.com0264fb42012-12-06 02:01:25 +0000611
reed@google.com1ea95be2012-11-09 21:39:48 +0000612 for (int i = 0; i < 4; i++) {
613 SkMScalar value = 0;
614 for (int j = 0; j < 4; j++) {
615 value += fMat[j][i] * src[j];
616 }
reed@google.com7d683352012-12-03 21:19:52 +0000617 result[i] = value;
reed@google.com1ea95be2012-11-09 21:39:48 +0000618 }
skia.committer@gmail.com0264fb42012-12-06 02:01:25 +0000619
reed@google.com7d683352012-12-03 21:19:52 +0000620 if (storage == result) {
621 memcpy(dst, storage, sizeof(storage));
622 }
reed@google.com1ea95be2012-11-09 21:39:48 +0000623}
reed@google.com7d683352012-12-03 21:19:52 +0000624
reed@google.com1ea95be2012-11-09 21:39:48 +0000625#endif
626
reed@google.com99b5c7f2012-12-05 22:13:59 +0000627typedef void (*Map2Procf)(const SkMScalar mat[][4], const float src2[], int count, float dst4[]);
628typedef void (*Map2Procd)(const SkMScalar mat[][4], const double src2[], int count, double dst4[]);
629
630static void map2_if(const SkMScalar mat[][4], const float* SK_RESTRICT src2,
631 int count, float* SK_RESTRICT dst4) {
632 for (int i = 0; i < count; ++i) {
633 dst4[0] = src2[0];
634 dst4[1] = src2[1];
635 dst4[2] = 0;
636 dst4[3] = 1;
637 src2 += 2;
638 dst4 += 4;
639 }
640}
641
642static void map2_id(const SkMScalar mat[][4], const double* SK_RESTRICT src2,
643 int count, double* SK_RESTRICT dst4) {
644 for (int i = 0; i < count; ++i) {
645 dst4[0] = src2[0];
646 dst4[1] = src2[1];
647 dst4[2] = 0;
648 dst4[3] = 1;
649 src2 += 2;
650 dst4 += 4;
651 }
652}
653
654static void map2_tf(const SkMScalar mat[][4], const float* SK_RESTRICT src2,
655 int count, float* SK_RESTRICT dst4) {
656 const float mat30 = SkMScalarToFloat(mat[3][0]);
657 const float mat31 = SkMScalarToFloat(mat[3][1]);
658 const float mat32 = SkMScalarToFloat(mat[3][2]);
659 for (int n = 0; n < count; ++n) {
660 dst4[0] = src2[0] + mat30;
661 dst4[1] = src2[1] + mat31;
662 dst4[2] = mat32;
663 dst4[3] = 1;
664 src2 += 2;
665 dst4 += 4;
666 }
667}
668
669static void map2_td(const SkMScalar mat[][4], const double* SK_RESTRICT src2,
670 int count, double* SK_RESTRICT dst4) {
671 for (int n = 0; n < count; ++n) {
672 dst4[0] = src2[0] + mat[3][0];
673 dst4[1] = src2[1] + mat[3][1];
674 dst4[2] = mat[3][2];
675 dst4[3] = 1;
676 src2 += 2;
677 dst4 += 4;
678 }
679}
680
681static void map2_sf(const SkMScalar mat[][4], const float* SK_RESTRICT src2,
682 int count, float* SK_RESTRICT dst4) {
683 const float mat32 = SkMScalarToFloat(mat[3][2]);
684 for (int n = 0; n < count; ++n) {
685 dst4[0] = SkMScalarToFloat(mat[0][0] * src2[0] + mat[3][0]);
686 dst4[1] = SkMScalarToFloat(mat[1][1] * src2[1] + mat[3][1]);
687 dst4[2] = mat32;
688 dst4[3] = 1;
689 src2 += 2;
690 dst4 += 4;
691 }
692}
693
694static void map2_sd(const SkMScalar mat[][4], const double* SK_RESTRICT src2,
695 int count, double* SK_RESTRICT dst4) {
696 for (int n = 0; n < count; ++n) {
697 dst4[0] = mat[0][0] * src2[0] + mat[3][0];
698 dst4[1] = mat[1][1] * src2[1] + mat[3][1];
699 dst4[2] = mat[3][2];
700 dst4[3] = 1;
701 src2 += 2;
702 dst4 += 4;
703 }
704}
705
706static void map2_af(const SkMScalar mat[][4], const float* SK_RESTRICT src2,
707 int count, float* SK_RESTRICT dst4) {
708 double r;
709 for (int n = 0; n < count; ++n) {
710 double sx = src2[0];
711 double sy = src2[1];
712 r = mat[0][0] * sx + mat[1][0] * sy + mat[3][0];
713 dst4[0] = SkMScalarToFloat(r);
714 r = mat[0][1] * sx + mat[1][1] * sy + mat[3][1];
715 dst4[1] = SkMScalarToFloat(r);
716 r = mat[0][2] * sx + mat[1][2] * sy + mat[3][2];
717 dst4[2] = SkMScalarToFloat(r);
718 dst4[3] = 1;
719 src2 += 2;
720 dst4 += 4;
721 }
722}
723
724static void map2_ad(const SkMScalar mat[][4], const double* SK_RESTRICT src2,
725 int count, double* SK_RESTRICT dst4) {
726 for (int n = 0; n < count; ++n) {
727 double sx = src2[0];
728 double sy = src2[1];
729 dst4[0] = mat[0][0] * sx + mat[1][0] * sy + mat[3][0];
730 dst4[1] = mat[0][1] * sx + mat[1][1] * sy + mat[3][1];
731 dst4[2] = mat[0][2] * sx + mat[1][2] * sy + mat[3][2];
732 dst4[3] = 1;
733 src2 += 2;
734 dst4 += 4;
735 }
736}
737
738static void map2_pf(const SkMScalar mat[][4], const float* SK_RESTRICT src2,
739 int count, float* SK_RESTRICT dst4) {
740 double r;
741 for (int n = 0; n < count; ++n) {
742 double sx = src2[0];
743 double sy = src2[1];
744 for (int i = 0; i < 4; i++) {
745 r = mat[0][i] * sx + mat[1][i] * sy + mat[3][i];
746 dst4[i] = SkMScalarToFloat(r);
747 }
748 src2 += 2;
749 dst4 += 4;
750 }
751}
752
753static void map2_pd(const SkMScalar mat[][4], const double* SK_RESTRICT src2,
754 int count, double* SK_RESTRICT dst4) {
755 for (int n = 0; n < count; ++n) {
756 double sx = src2[0];
757 double sy = src2[1];
758 for (int i = 0; i < 4; i++) {
759 dst4[i] = mat[0][i] * sx + mat[1][i] * sy + mat[3][i];
760 }
761 src2 += 2;
762 dst4 += 4;
763 }
764}
765
766void SkMatrix44::map2(const float src2[], int count, float dst4[]) const {
767 static const Map2Procf gProc[] = {
768 map2_if, map2_tf, map2_sf, map2_sf, map2_af, map2_af, map2_af, map2_af
769 };
770
771 TypeMask mask = this->getType();
772 Map2Procf proc = (mask & kPerspective_Mask) ? map2_pf : gProc[mask];
773 proc(fMat, src2, count, dst4);
774}
775
776void SkMatrix44::map2(const double src2[], int count, double dst4[]) const {
777 static const Map2Procd gProc[] = {
778 map2_id, map2_td, map2_sd, map2_sd, map2_ad, map2_ad, map2_ad, map2_ad
779 };
skia.committer@gmail.com0264fb42012-12-06 02:01:25 +0000780
reed@google.com99b5c7f2012-12-05 22:13:59 +0000781 TypeMask mask = this->getType();
782 Map2Procd proc = (mask & kPerspective_Mask) ? map2_pd : gProc[mask];
783 proc(fMat, src2, count, dst4);
784}
785
reed@google.com8260a892011-06-13 14:02:52 +0000786///////////////////////////////////////////////////////////////////////////////
787
788void SkMatrix44::dump() const {
tomhudson@google.com9ac4a892011-06-28 13:53:13 +0000789 static const char* format =
790 "[%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 +0000791#if 0
tomhudson@google.com9ac4a892011-06-28 13:53:13 +0000792 SkDebugf(format,
reed@google.com8260a892011-06-13 14:02:52 +0000793 fMat[0][0], fMat[1][0], fMat[2][0], fMat[3][0],
794 fMat[0][1], fMat[1][1], fMat[2][1], fMat[3][1],
795 fMat[0][2], fMat[1][2], fMat[2][2], fMat[3][2],
796 fMat[0][3], fMat[1][3], fMat[2][3], fMat[3][3]);
tomhudson@google.com9ac4a892011-06-28 13:53:13 +0000797#else
798 SkDebugf(format,
799 fMat[0][0], fMat[0][1], fMat[0][2], fMat[0][3],
800 fMat[1][0], fMat[1][1], fMat[1][2], fMat[1][3],
801 fMat[2][0], fMat[2][1], fMat[2][2], fMat[2][3],
802 fMat[3][0], fMat[3][1], fMat[3][2], fMat[3][3]);
reed@google.com8260a892011-06-13 14:02:52 +0000803#endif
804}
805
806///////////////////////////////////////////////////////////////////////////////
807
reed@google.com7d683352012-12-03 21:19:52 +0000808// TODO: make this support src' perspective elements
809//
reed@google.com8260a892011-06-13 14:02:52 +0000810static void initFromMatrix(SkMScalar dst[4][4], const SkMatrix& src) {
811 sk_bzero(dst, 16 * sizeof(SkMScalar));
bsalomon@google.com72e49b82011-10-27 21:47:03 +0000812 dst[0][0] = SkScalarToMScalar(src[SkMatrix::kMScaleX]);
813 dst[1][0] = SkScalarToMScalar(src[SkMatrix::kMSkewX]);
814 dst[3][0] = SkScalarToMScalar(src[SkMatrix::kMTransX]);
815 dst[0][1] = SkScalarToMScalar(src[SkMatrix::kMSkewY]);
816 dst[1][1] = SkScalarToMScalar(src[SkMatrix::kMScaleY]);
817 dst[3][1] = SkScalarToMScalar(src[SkMatrix::kMTransY]);
reed@google.com8260a892011-06-13 14:02:52 +0000818 dst[2][2] = dst[3][3] = 1;
819}
820
821SkMatrix44::SkMatrix44(const SkMatrix& src) {
822 initFromMatrix(fMat, src);
823}
824
825SkMatrix44& SkMatrix44::operator=(const SkMatrix& src) {
826 initFromMatrix(fMat, src);
reed@google.com7d683352012-12-03 21:19:52 +0000827
828 if (src.isIdentity()) {
829 this->setTypeMask(kIdentity_Mask);
830 } else {
831 this->dirtyTypeMask();
832 }
reed@google.com8260a892011-06-13 14:02:52 +0000833 return *this;
834}
835
reed@google.com7d683352012-12-03 21:19:52 +0000836// TODO: make this support our perspective elements
837//
reed@google.com8260a892011-06-13 14:02:52 +0000838SkMatrix44::operator SkMatrix() const {
839 SkMatrix dst;
840 dst.reset(); // setup our perspective correctly for identity
841
bsalomon@google.com72e49b82011-10-27 21:47:03 +0000842 dst[SkMatrix::kMScaleX] = SkMScalarToScalar(fMat[0][0]);
843 dst[SkMatrix::kMSkewX] = SkMScalarToScalar(fMat[1][0]);
844 dst[SkMatrix::kMTransX] = SkMScalarToScalar(fMat[3][0]);
reed@google.com8260a892011-06-13 14:02:52 +0000845
bsalomon@google.com72e49b82011-10-27 21:47:03 +0000846 dst[SkMatrix::kMSkewY] = SkMScalarToScalar(fMat[0][1]);
847 dst[SkMatrix::kMScaleY] = SkMScalarToScalar(fMat[1][1]);
848 dst[SkMatrix::kMTransY] = SkMScalarToScalar(fMat[3][1]);
reed@google.com8260a892011-06-13 14:02:52 +0000849
850 return dst;
851}