blob: 5953da648c9c4e766c83a2983f7748579f1832e8 [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
tomhudson@google.com21e43222013-01-17 12:17:00 +0000346#if defined(SK_MATRIX44_USE_SSE2)
347#include <emmintrin.h>
348struct MatrixD {
349 __m128d x_xy, x_zw;
350 __m128d y_xy, y_zw;
351 __m128d z_xy, z_zw;
352 __m128d w_xy, w_zw;
353};
354
355#if defined(_MSC_VER)
356inline __m128d operator +(__m128d a, __m128d b) { return _mm_add_pd(a, b); }
357inline __m128d operator *(__m128d a, __m128d b) { return _mm_mul_pd(a, b); }
358#endif
359#endif
360
reed@google.com8260a892011-06-13 14:02:52 +0000361void SkMatrix44::setConcat(const SkMatrix44& a, const SkMatrix44& b) {
reed@google.com99b5c7f2012-12-05 22:13:59 +0000362 const SkMatrix44::TypeMask a_mask = a.getType();
363 const SkMatrix44::TypeMask b_mask = b.getType();
364
365 if (kIdentity_Mask == a_mask) {
reed@google.com7d683352012-12-03 21:19:52 +0000366 *this = b;
367 return;
368 }
reed@google.com99b5c7f2012-12-05 22:13:59 +0000369 if (kIdentity_Mask == b_mask) {
reed@google.com7d683352012-12-03 21:19:52 +0000370 *this = a;
371 return;
372 }
373
374 bool useStorage = (this == &a || this == &b);
tomhudson@google.com21e43222013-01-17 12:17:00 +0000375#if defined(SK_MATRIX44_USE_SSE2)
376 MatrixD storage;
377 SkMScalar* result = useStorage ? (SkMScalar*)&storage : &fMat[0][0];
378#else
reed@google.com7d683352012-12-03 21:19:52 +0000379 SkMScalar storage[16];
380 SkMScalar* result = useStorage ? storage : &fMat[0][0];
tomhudson@google.com21e43222013-01-17 12:17:00 +0000381#endif
reed@google.com7d683352012-12-03 21:19:52 +0000382
reed@google.com99b5c7f2012-12-05 22:13:59 +0000383 if (bits_isonly(a_mask | b_mask, kScale_Mask | kTranslate_Mask)) {
reed@google.com99b5c7f2012-12-05 22:13:59 +0000384 result[0] = a.fMat[0][0] * b.fMat[0][0];
tomhudson@google.com21e43222013-01-17 12:17:00 +0000385 result[1] = 0.0;
386 result[2] = 0.0;
387 result[3] = 0.0;
388 result[4] = 0.0;
reed@google.com99b5c7f2012-12-05 22:13:59 +0000389 result[5] = a.fMat[1][1] * b.fMat[1][1];
tomhudson@google.com21e43222013-01-17 12:17:00 +0000390 result[6] = 0.0;
391 result[7] = 0.0;
392 result[8] = 0.0;
393 result[9] = 0.0;
reed@google.com99b5c7f2012-12-05 22:13:59 +0000394 result[10] = a.fMat[2][2] * b.fMat[2][2];
tomhudson@google.com21e43222013-01-17 12:17:00 +0000395 result[11] = 0.0;
reed@google.com99b5c7f2012-12-05 22:13:59 +0000396 result[12] = a.fMat[0][0] * b.fMat[3][0] + a.fMat[3][0];
397 result[13] = a.fMat[1][1] * b.fMat[3][1] + a.fMat[3][1];
398 result[14] = a.fMat[2][2] * b.fMat[3][2] + a.fMat[3][2];
399 result[15] = 1;
400 } else {
tomhudson@google.com21e43222013-01-17 12:17:00 +0000401#if defined(SK_MATRIX44_USE_SSE2)
402 MatrixD* p = (MatrixD*)result;
403 const MatrixD* pa = (const MatrixD*)a.fMat;
404 const MatrixD* pb = (const MatrixD*)b.fMat;
405 __m128d x_xy = pa->x_xy;
406 __m128d x_zw = pa->x_zw;
407 __m128d y_xy = pa->y_xy;
408 __m128d y_zw = pa->y_zw;
409 __m128d z_xy = pa->z_xy;
410 __m128d z_zw = pa->z_zw;
411 __m128d w_xy = pa->w_xy;
412 __m128d w_zw = pa->w_zw;
413 __m128d b0, b1, b2, b3;
414 b0 = _mm_set1_pd(((double*)&pb->x_xy)[0]);
415 b1 = _mm_set1_pd(((double*)&pb->x_xy)[1]);
416 b2 = _mm_set1_pd(((double*)&pb->x_zw)[0]);
417 b3 = _mm_set1_pd(((double*)&pb->x_zw)[1]);
418 p->x_xy = b0 * x_xy + b1 * y_xy + b2 * z_xy + b3 * w_xy;
419 p->x_zw = b0 * x_zw + b1 * y_zw + b2 * z_zw + b3 * w_zw;
420 b0 = _mm_set1_pd(((double*)&pb->y_xy)[0]);
421 b1 = _mm_set1_pd(((double*)&pb->y_xy)[1]);
422 b2 = _mm_set1_pd(((double*)&pb->y_zw)[0]);
423 b3 = _mm_set1_pd(((double*)&pb->y_zw)[1]);
424 p->y_xy = b0 * x_xy + b1 * y_xy + b2 * z_xy + b3 * w_xy;
425 p->y_zw = b0 * x_zw + b1 * y_zw + b2 * z_zw + b3 * w_zw;
426 b0 = _mm_set1_pd(((double*)&pb->z_xy)[0]);
427 b1 = _mm_set1_pd(((double*)&pb->z_xy)[1]);
428 b2 = _mm_set1_pd(((double*)&pb->z_zw)[0]);
429 b3 = _mm_set1_pd(((double*)&pb->z_zw)[1]);
430 p->z_xy = b0 * x_xy + b1 * y_xy + b2 * z_xy + b3 * w_xy;
431 p->z_zw = b0 * x_zw + b1 * y_zw + b2 * z_zw + b3 * w_zw;
432 b0 = _mm_set1_pd(((double*)&pb->w_xy)[0]);
433 b1 = _mm_set1_pd(((double*)&pb->w_xy)[1]);
434 b2 = _mm_set1_pd(((double*)&pb->w_zw)[0]);
435 b3 = _mm_set1_pd(((double*)&pb->w_zw)[1]);
436 p->w_xy = b0 * x_xy + b1 * y_xy + b2 * z_xy + b3 * w_xy;
437 p->w_zw = b0 * x_zw + b1 * y_zw + b2 * z_zw + b3 * w_zw;
438#else
reed@google.com99b5c7f2012-12-05 22:13:59 +0000439 for (int j = 0; j < 4; j++) {
440 for (int i = 0; i < 4; i++) {
441 double value = 0;
442 for (int k = 0; k < 4; k++) {
443 value += SkMScalarToDouble(a.fMat[k][i]) * b.fMat[j][k];
444 }
445 *result++ = SkDoubleToMScalar(value);
reed@google.com8260a892011-06-13 14:02:52 +0000446 }
reed@google.com8260a892011-06-13 14:02:52 +0000447 }
tomhudson@google.com21e43222013-01-17 12:17:00 +0000448#endif
reed@google.com8260a892011-06-13 14:02:52 +0000449 }
reed@google.com99b5c7f2012-12-05 22:13:59 +0000450
reed@google.com7d683352012-12-03 21:19:52 +0000451 if (useStorage) {
tomhudson@google.com21e43222013-01-17 12:17:00 +0000452 memcpy(fMat, result, sizeof(storage));
reed@google.com7d683352012-12-03 21:19:52 +0000453 }
reed@google.com7d683352012-12-03 21:19:52 +0000454 this->dirtyTypeMask();
reed@google.com8260a892011-06-13 14:02:52 +0000455}
456
457///////////////////////////////////////////////////////////////////////////////
458
459static inline SkMScalar det2x2(double m00, double m01, double m10, double m11) {
bsalomon@google.com9d12f5c2011-09-29 18:08:18 +0000460 return SkDoubleToMScalar(m00 * m11 - m10 * m01);
reed@google.com8260a892011-06-13 14:02:52 +0000461}
462
463static inline double det3x3(double m00, double m01, double m02,
464 double m10, double m11, double m12,
465 double m20, double m21, double m22) {
466 return m00 * det2x2(m11, m12, m21, m22) -
467 m10 * det2x2(m01, m02, m21, m22) +
468 m20 * det2x2(m01, m02, m11, m12);
469}
470
471/** We always perform the calculation in doubles, to avoid prematurely losing
472 precision along the way. This relies on the compiler automatically
473 promoting our SkMScalar values to double (if needed).
474 */
475double SkMatrix44::determinant() const {
mike@reedtribe.orgf8b1ebc2012-12-10 03:27:47 +0000476 if (this->isIdentity()) {
477 return 1;
478 }
479 if (this->isScaleTranslate()) {
480 return fMat[0][0] * fMat[1][1] * fMat[2][2] * fMat[3][3];
481 }
482
tomhudson@google.com9973a8a2012-12-13 09:55:42 +0000483 double a00 = fMat[0][0];
484 double a01 = fMat[0][1];
485 double a02 = fMat[0][2];
486 double a03 = fMat[0][3];
487 double a10 = fMat[1][0];
488 double a11 = fMat[1][1];
489 double a12 = fMat[1][2];
490 double a13 = fMat[1][3];
491 double a20 = fMat[2][0];
492 double a21 = fMat[2][1];
493 double a22 = fMat[2][2];
494 double a23 = fMat[2][3];
495 double a30 = fMat[3][0];
496 double a31 = fMat[3][1];
497 double a32 = fMat[3][2];
498 double a33 = fMat[3][3];
499
500 double b00 = a00 * a11 - a01 * a10;
501 double b01 = a00 * a12 - a02 * a10;
502 double b02 = a00 * a13 - a03 * a10;
503 double b03 = a01 * a12 - a02 * a11;
504 double b04 = a01 * a13 - a03 * a11;
505 double b05 = a02 * a13 - a03 * a12;
506 double b06 = a20 * a31 - a21 * a30;
507 double b07 = a20 * a32 - a22 * a30;
508 double b08 = a20 * a33 - a23 * a30;
509 double b09 = a21 * a32 - a22 * a31;
510 double b10 = a21 * a33 - a23 * a31;
511 double b11 = a22 * a33 - a23 * a32;
512
513 // Calculate the determinant
514 return b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
reed@google.com8260a892011-06-13 14:02:52 +0000515}
516
517///////////////////////////////////////////////////////////////////////////////
518
519// just picked a small value. not sure how to pick the "right" one
520#define TOO_SMALL_FOR_DETERMINANT (1.e-8)
521
522static inline double dabs(double x) {
523 if (x < 0) {
524 x = -x;
525 }
526 return x;
527}
528
529bool SkMatrix44::invert(SkMatrix44* inverse) const {
mike@reedtribe.orgf8b1ebc2012-12-10 03:27:47 +0000530 if (this->isIdentity()) {
reed@google.com7d683352012-12-03 21:19:52 +0000531 if (inverse) {
532 *inverse = *this;
533 return true;
534 }
535 }
mike@reedtribe.orgf8b1ebc2012-12-10 03:27:47 +0000536 if (this->isTranslate()) {
reed@google.com99b5c7f2012-12-05 22:13:59 +0000537 if (inverse) {
538 inverse->setTranslate(-fMat[3][0], -fMat[3][1], -fMat[3][2]);
539 }
540 return true;
541 }
mike@reedtribe.orgf8b1ebc2012-12-10 03:27:47 +0000542 if (this->isScaleTranslate()) {
reed@google.com99b5c7f2012-12-05 22:13:59 +0000543 if (0 == fMat[0][0] * fMat[1][1] * fMat[2][2]) {
544 return false;
545 }
546 if (inverse) {
547 sk_bzero(inverse->fMat, sizeof(inverse->fMat));
548
549 inverse->fMat[3][0] = -fMat[3][0] / fMat[0][0];
550 inverse->fMat[3][1] = -fMat[3][1] / fMat[1][1];
551 inverse->fMat[3][2] = -fMat[3][2] / fMat[2][2];
552
553 inverse->fMat[0][0] = 1 / fMat[0][0];
554 inverse->fMat[1][1] = 1 / fMat[1][1];
555 inverse->fMat[2][2] = 1 / fMat[2][2];
556 inverse->fMat[3][3] = 1;
557
mike@reedtribe.orgf8b1ebc2012-12-10 03:27:47 +0000558 inverse->setTypeMask(this->getType());
reed@google.com99b5c7f2012-12-05 22:13:59 +0000559 }
560 return true;
561 }
562
tomhudson@google.com9973a8a2012-12-13 09:55:42 +0000563 double a00 = fMat[0][0];
564 double a01 = fMat[0][1];
565 double a02 = fMat[0][2];
566 double a03 = fMat[0][3];
567 double a10 = fMat[1][0];
568 double a11 = fMat[1][1];
569 double a12 = fMat[1][2];
570 double a13 = fMat[1][3];
571 double a20 = fMat[2][0];
572 double a21 = fMat[2][1];
573 double a22 = fMat[2][2];
574 double a23 = fMat[2][3];
575 double a30 = fMat[3][0];
576 double a31 = fMat[3][1];
577 double a32 = fMat[3][2];
578 double a33 = fMat[3][3];
579
580 double b00 = a00 * a11 - a01 * a10;
581 double b01 = a00 * a12 - a02 * a10;
582 double b02 = a00 * a13 - a03 * a10;
583 double b03 = a01 * a12 - a02 * a11;
584 double b04 = a01 * a13 - a03 * a11;
585 double b05 = a02 * a13 - a03 * a12;
586 double b06 = a20 * a31 - a21 * a30;
587 double b07 = a20 * a32 - a22 * a30;
588 double b08 = a20 * a33 - a23 * a30;
589 double b09 = a21 * a32 - a22 * a31;
590 double b10 = a21 * a33 - a23 * a31;
591 double b11 = a22 * a33 - a23 * a32;
592
593 // Calculate the determinant
594 double det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
595
reed@google.com8260a892011-06-13 14:02:52 +0000596 if (dabs(det) < TOO_SMALL_FOR_DETERMINANT) {
597 return false;
598 }
599 if (NULL == inverse) {
600 return true;
601 }
tomhudson@google.com9973a8a2012-12-13 09:55:42 +0000602 double invdet = 1.0 / det;
reed@google.com8260a892011-06-13 14:02:52 +0000603
tomhudson@google.com9973a8a2012-12-13 09:55:42 +0000604 b00 *= invdet;
605 b01 *= invdet;
606 b02 *= invdet;
607 b03 *= invdet;
608 b04 *= invdet;
609 b05 *= invdet;
610 b06 *= invdet;
611 b07 *= invdet;
612 b08 *= invdet;
613 b09 *= invdet;
614 b10 *= invdet;
615 b11 *= invdet;
reed@google.com8260a892011-06-13 14:02:52 +0000616
tomhudson@google.com9973a8a2012-12-13 09:55:42 +0000617 inverse->fMat[0][0] = SkDoubleToMScalar(a11 * b11 - a12 * b10 + a13 * b09);
618 inverse->fMat[0][1] = SkDoubleToMScalar(a02 * b10 - a01 * b11 - a03 * b09);
619 inverse->fMat[0][2] = SkDoubleToMScalar(a31 * b05 - a32 * b04 + a33 * b03);
620 inverse->fMat[0][3] = SkDoubleToMScalar(a22 * b04 - a21 * b05 - a23 * b03);
621 inverse->fMat[1][0] = SkDoubleToMScalar(a12 * b08 - a10 * b11 - a13 * b07);
622 inverse->fMat[1][1] = SkDoubleToMScalar(a00 * b11 - a02 * b08 + a03 * b07);
623 inverse->fMat[1][2] = SkDoubleToMScalar(a32 * b02 - a30 * b05 - a33 * b01);
624 inverse->fMat[1][3] = SkDoubleToMScalar(a20 * b05 - a22 * b02 + a23 * b01);
625 inverse->fMat[2][0] = SkDoubleToMScalar(a10 * b10 - a11 * b08 + a13 * b06);
626 inverse->fMat[2][1] = SkDoubleToMScalar(a01 * b08 - a00 * b10 - a03 * b06);
627 inverse->fMat[2][2] = SkDoubleToMScalar(a30 * b04 - a31 * b02 + a33 * b00);
628 inverse->fMat[2][3] = SkDoubleToMScalar(a21 * b02 - a20 * b04 - a23 * b00);
629 inverse->fMat[3][0] = SkDoubleToMScalar(a11 * b07 - a10 * b09 - a12 * b06);
630 inverse->fMat[3][1] = SkDoubleToMScalar(a00 * b09 - a01 * b07 + a02 * b06);
631 inverse->fMat[3][2] = SkDoubleToMScalar(a31 * b01 - a30 * b03 - a32 * b00);
632 inverse->fMat[3][3] = SkDoubleToMScalar(a20 * b03 - a21 * b01 + a22 * b00);
633 inverse->dirtyTypeMask();
reed@google.com8260a892011-06-13 14:02:52 +0000634
reed@google.com7d683352012-12-03 21:19:52 +0000635 inverse->dirtyTypeMask();
reed@google.com8260a892011-06-13 14:02:52 +0000636 return true;
637}
638
639///////////////////////////////////////////////////////////////////////////////
640
vollick@chromium.org9b21c252012-11-14 21:33:55 +0000641void SkMatrix44::transpose() {
642 SkTSwap(fMat[0][1], fMat[1][0]);
643 SkTSwap(fMat[0][2], fMat[2][0]);
644 SkTSwap(fMat[0][3], fMat[3][0]);
645 SkTSwap(fMat[1][2], fMat[2][1]);
646 SkTSwap(fMat[1][3], fMat[3][1]);
647 SkTSwap(fMat[2][3], fMat[3][2]);
reed@google.com7d683352012-12-03 21:19:52 +0000648
649 if (!this->isTriviallyIdentity()) {
650 this->dirtyTypeMask();
651 }
vollick@chromium.org9b21c252012-11-14 21:33:55 +0000652}
653
654///////////////////////////////////////////////////////////////////////////////
655
reed@google.com1ea95be2012-11-09 21:39:48 +0000656void SkMatrix44::mapScalars(const SkScalar src[4], SkScalar dst[4]) const {
reed@google.com7d683352012-12-03 21:19:52 +0000657 SkScalar storage[4];
658 SkScalar* result = (src == dst) ? storage : dst;
659
reed@google.com8260a892011-06-13 14:02:52 +0000660 for (int i = 0; i < 4; i++) {
661 SkMScalar value = 0;
662 for (int j = 0; j < 4; j++) {
663 value += fMat[j][i] * src[j];
664 }
bsalomon@google.com72e49b82011-10-27 21:47:03 +0000665 result[i] = SkMScalarToScalar(value);
reed@google.com8260a892011-06-13 14:02:52 +0000666 }
skia.committer@gmail.com0264fb42012-12-06 02:01:25 +0000667
reed@google.com7d683352012-12-03 21:19:52 +0000668 if (storage == result) {
669 memcpy(dst, storage, sizeof(storage));
670 }
reed@google.com8260a892011-06-13 14:02:52 +0000671}
672
reed@google.com1ea95be2012-11-09 21:39:48 +0000673#ifdef SK_MSCALAR_IS_DOUBLE
reed@google.com7d683352012-12-03 21:19:52 +0000674
reed@google.com1ea95be2012-11-09 21:39:48 +0000675void SkMatrix44::mapMScalars(const SkMScalar src[4], SkMScalar dst[4]) const {
reed@google.com7d683352012-12-03 21:19:52 +0000676 SkMScalar storage[4];
677 SkMScalar* result = (src == dst) ? storage : dst;
skia.committer@gmail.com0264fb42012-12-06 02:01:25 +0000678
reed@google.com1ea95be2012-11-09 21:39:48 +0000679 for (int i = 0; i < 4; i++) {
680 SkMScalar value = 0;
681 for (int j = 0; j < 4; j++) {
682 value += fMat[j][i] * src[j];
683 }
reed@google.com7d683352012-12-03 21:19:52 +0000684 result[i] = value;
reed@google.com1ea95be2012-11-09 21:39:48 +0000685 }
skia.committer@gmail.com0264fb42012-12-06 02:01:25 +0000686
reed@google.com7d683352012-12-03 21:19:52 +0000687 if (storage == result) {
688 memcpy(dst, storage, sizeof(storage));
689 }
reed@google.com1ea95be2012-11-09 21:39:48 +0000690}
reed@google.com7d683352012-12-03 21:19:52 +0000691
reed@google.com1ea95be2012-11-09 21:39:48 +0000692#endif
693
reed@google.com99b5c7f2012-12-05 22:13:59 +0000694typedef void (*Map2Procf)(const SkMScalar mat[][4], const float src2[], int count, float dst4[]);
695typedef void (*Map2Procd)(const SkMScalar mat[][4], const double src2[], int count, double dst4[]);
696
697static void map2_if(const SkMScalar mat[][4], const float* SK_RESTRICT src2,
698 int count, float* SK_RESTRICT dst4) {
699 for (int i = 0; i < count; ++i) {
700 dst4[0] = src2[0];
701 dst4[1] = src2[1];
702 dst4[2] = 0;
703 dst4[3] = 1;
704 src2 += 2;
705 dst4 += 4;
706 }
707}
708
709static void map2_id(const SkMScalar mat[][4], const double* SK_RESTRICT src2,
710 int count, double* SK_RESTRICT dst4) {
711 for (int i = 0; i < count; ++i) {
712 dst4[0] = src2[0];
713 dst4[1] = src2[1];
714 dst4[2] = 0;
715 dst4[3] = 1;
716 src2 += 2;
717 dst4 += 4;
718 }
719}
720
721static void map2_tf(const SkMScalar mat[][4], const float* SK_RESTRICT src2,
722 int count, float* SK_RESTRICT dst4) {
723 const float mat30 = SkMScalarToFloat(mat[3][0]);
724 const float mat31 = SkMScalarToFloat(mat[3][1]);
725 const float mat32 = SkMScalarToFloat(mat[3][2]);
726 for (int n = 0; n < count; ++n) {
727 dst4[0] = src2[0] + mat30;
728 dst4[1] = src2[1] + mat31;
729 dst4[2] = mat32;
730 dst4[3] = 1;
731 src2 += 2;
732 dst4 += 4;
733 }
734}
735
736static void map2_td(const SkMScalar mat[][4], const double* SK_RESTRICT src2,
737 int count, double* SK_RESTRICT dst4) {
738 for (int n = 0; n < count; ++n) {
739 dst4[0] = src2[0] + mat[3][0];
740 dst4[1] = src2[1] + mat[3][1];
741 dst4[2] = mat[3][2];
742 dst4[3] = 1;
743 src2 += 2;
744 dst4 += 4;
745 }
746}
747
748static void map2_sf(const SkMScalar mat[][4], const float* SK_RESTRICT src2,
749 int count, float* SK_RESTRICT dst4) {
750 const float mat32 = SkMScalarToFloat(mat[3][2]);
751 for (int n = 0; n < count; ++n) {
752 dst4[0] = SkMScalarToFloat(mat[0][0] * src2[0] + mat[3][0]);
753 dst4[1] = SkMScalarToFloat(mat[1][1] * src2[1] + mat[3][1]);
754 dst4[2] = mat32;
755 dst4[3] = 1;
756 src2 += 2;
757 dst4 += 4;
758 }
759}
760
761static void map2_sd(const SkMScalar mat[][4], const double* SK_RESTRICT src2,
762 int count, double* SK_RESTRICT dst4) {
763 for (int n = 0; n < count; ++n) {
764 dst4[0] = mat[0][0] * src2[0] + mat[3][0];
765 dst4[1] = mat[1][1] * src2[1] + mat[3][1];
766 dst4[2] = mat[3][2];
767 dst4[3] = 1;
768 src2 += 2;
769 dst4 += 4;
770 }
771}
772
773static void map2_af(const SkMScalar mat[][4], const float* SK_RESTRICT src2,
774 int count, float* SK_RESTRICT dst4) {
775 double r;
776 for (int n = 0; n < count; ++n) {
777 double sx = src2[0];
778 double sy = src2[1];
779 r = mat[0][0] * sx + mat[1][0] * sy + mat[3][0];
780 dst4[0] = SkMScalarToFloat(r);
781 r = mat[0][1] * sx + mat[1][1] * sy + mat[3][1];
782 dst4[1] = SkMScalarToFloat(r);
783 r = mat[0][2] * sx + mat[1][2] * sy + mat[3][2];
784 dst4[2] = SkMScalarToFloat(r);
785 dst4[3] = 1;
786 src2 += 2;
787 dst4 += 4;
788 }
789}
790
791static void map2_ad(const SkMScalar mat[][4], const double* SK_RESTRICT src2,
792 int count, double* SK_RESTRICT dst4) {
793 for (int n = 0; n < count; ++n) {
794 double sx = src2[0];
795 double sy = src2[1];
796 dst4[0] = mat[0][0] * sx + mat[1][0] * sy + mat[3][0];
797 dst4[1] = mat[0][1] * sx + mat[1][1] * sy + mat[3][1];
798 dst4[2] = mat[0][2] * sx + mat[1][2] * sy + mat[3][2];
799 dst4[3] = 1;
800 src2 += 2;
801 dst4 += 4;
802 }
803}
804
805static void map2_pf(const SkMScalar mat[][4], const float* SK_RESTRICT src2,
806 int count, float* SK_RESTRICT dst4) {
807 double r;
808 for (int n = 0; n < count; ++n) {
809 double sx = src2[0];
810 double sy = src2[1];
811 for (int i = 0; i < 4; i++) {
812 r = mat[0][i] * sx + mat[1][i] * sy + mat[3][i];
813 dst4[i] = SkMScalarToFloat(r);
814 }
815 src2 += 2;
816 dst4 += 4;
817 }
818}
819
820static void map2_pd(const SkMScalar mat[][4], const double* SK_RESTRICT src2,
821 int count, double* SK_RESTRICT dst4) {
822 for (int n = 0; n < count; ++n) {
823 double sx = src2[0];
824 double sy = src2[1];
825 for (int i = 0; i < 4; i++) {
826 dst4[i] = mat[0][i] * sx + mat[1][i] * sy + mat[3][i];
827 }
828 src2 += 2;
829 dst4 += 4;
830 }
831}
832
833void SkMatrix44::map2(const float src2[], int count, float dst4[]) const {
834 static const Map2Procf gProc[] = {
835 map2_if, map2_tf, map2_sf, map2_sf, map2_af, map2_af, map2_af, map2_af
836 };
837
838 TypeMask mask = this->getType();
839 Map2Procf proc = (mask & kPerspective_Mask) ? map2_pf : gProc[mask];
840 proc(fMat, src2, count, dst4);
841}
842
843void SkMatrix44::map2(const double src2[], int count, double dst4[]) const {
844 static const Map2Procd gProc[] = {
845 map2_id, map2_td, map2_sd, map2_sd, map2_ad, map2_ad, map2_ad, map2_ad
846 };
skia.committer@gmail.com0264fb42012-12-06 02:01:25 +0000847
reed@google.com99b5c7f2012-12-05 22:13:59 +0000848 TypeMask mask = this->getType();
849 Map2Procd proc = (mask & kPerspective_Mask) ? map2_pd : gProc[mask];
850 proc(fMat, src2, count, dst4);
851}
852
reed@google.com8260a892011-06-13 14:02:52 +0000853///////////////////////////////////////////////////////////////////////////////
854
855void SkMatrix44::dump() const {
tomhudson@google.com9ac4a892011-06-28 13:53:13 +0000856 static const char* format =
857 "[%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 +0000858#if 0
tomhudson@google.com9ac4a892011-06-28 13:53:13 +0000859 SkDebugf(format,
reed@google.com8260a892011-06-13 14:02:52 +0000860 fMat[0][0], fMat[1][0], fMat[2][0], fMat[3][0],
861 fMat[0][1], fMat[1][1], fMat[2][1], fMat[3][1],
862 fMat[0][2], fMat[1][2], fMat[2][2], fMat[3][2],
863 fMat[0][3], fMat[1][3], fMat[2][3], fMat[3][3]);
tomhudson@google.com9ac4a892011-06-28 13:53:13 +0000864#else
865 SkDebugf(format,
866 fMat[0][0], fMat[0][1], fMat[0][2], fMat[0][3],
867 fMat[1][0], fMat[1][1], fMat[1][2], fMat[1][3],
868 fMat[2][0], fMat[2][1], fMat[2][2], fMat[2][3],
869 fMat[3][0], fMat[3][1], fMat[3][2], fMat[3][3]);
reed@google.com8260a892011-06-13 14:02:52 +0000870#endif
871}
872
873///////////////////////////////////////////////////////////////////////////////
874
reed@google.com7d683352012-12-03 21:19:52 +0000875// TODO: make this support src' perspective elements
876//
reed@google.com8260a892011-06-13 14:02:52 +0000877static void initFromMatrix(SkMScalar dst[4][4], const SkMatrix& src) {
878 sk_bzero(dst, 16 * sizeof(SkMScalar));
bsalomon@google.com72e49b82011-10-27 21:47:03 +0000879 dst[0][0] = SkScalarToMScalar(src[SkMatrix::kMScaleX]);
880 dst[1][0] = SkScalarToMScalar(src[SkMatrix::kMSkewX]);
881 dst[3][0] = SkScalarToMScalar(src[SkMatrix::kMTransX]);
882 dst[0][1] = SkScalarToMScalar(src[SkMatrix::kMSkewY]);
883 dst[1][1] = SkScalarToMScalar(src[SkMatrix::kMScaleY]);
884 dst[3][1] = SkScalarToMScalar(src[SkMatrix::kMTransY]);
reed@google.com8260a892011-06-13 14:02:52 +0000885 dst[2][2] = dst[3][3] = 1;
886}
887
888SkMatrix44::SkMatrix44(const SkMatrix& src) {
889 initFromMatrix(fMat, src);
890}
891
892SkMatrix44& SkMatrix44::operator=(const SkMatrix& src) {
893 initFromMatrix(fMat, src);
reed@google.com7d683352012-12-03 21:19:52 +0000894
895 if (src.isIdentity()) {
896 this->setTypeMask(kIdentity_Mask);
897 } else {
898 this->dirtyTypeMask();
899 }
reed@google.com8260a892011-06-13 14:02:52 +0000900 return *this;
901}
902
reed@google.com7d683352012-12-03 21:19:52 +0000903// TODO: make this support our perspective elements
904//
reed@google.com8260a892011-06-13 14:02:52 +0000905SkMatrix44::operator SkMatrix() const {
906 SkMatrix dst;
907 dst.reset(); // setup our perspective correctly for identity
908
bsalomon@google.com72e49b82011-10-27 21:47:03 +0000909 dst[SkMatrix::kMScaleX] = SkMScalarToScalar(fMat[0][0]);
910 dst[SkMatrix::kMSkewX] = SkMScalarToScalar(fMat[1][0]);
911 dst[SkMatrix::kMTransX] = SkMScalarToScalar(fMat[3][0]);
reed@google.com8260a892011-06-13 14:02:52 +0000912
bsalomon@google.com72e49b82011-10-27 21:47:03 +0000913 dst[SkMatrix::kMSkewY] = SkMScalarToScalar(fMat[0][1]);
914 dst[SkMatrix::kMScaleY] = SkMScalarToScalar(fMat[1][1]);
915 dst[SkMatrix::kMTransY] = SkMScalarToScalar(fMat[3][1]);
reed@google.com8260a892011-06-13 14:02:52 +0000916
917 return dst;
918}