blob: 56c2e8a1428ab6eccabadc521a8eaf76b1e69305 [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
msarett111a42d2016-06-22 08:18:54 -070088void SkMatrix44::as4x3ColMajorf(float dst[]) const {
89 const SkMScalar* src = &fMat[0][0];
90#ifdef SK_MSCALAR_IS_DOUBLE
91 for (int i = 0; i < 12; ++i) {
92 dst[i] = SkMScalarToFloat(src[i]);
93 }
94#elif defined SK_MSCALAR_IS_FLOAT
95 memcpy(dst, src, 12 * sizeof(float));
96#endif
97}
98
reed@google.comda9fac02011-06-13 14:46:52 +000099void SkMatrix44::asColMajord(double dst[]) const {
100 const SkMScalar* src = &fMat[0][0];
101#ifdef SK_MSCALAR_IS_DOUBLE
102 memcpy(dst, src, 16 * sizeof(double));
vollick@chromium.org5596a692012-11-13 20:12:00 +0000103#elif defined SK_MSCALAR_IS_FLOAT
reed@google.comda9fac02011-06-13 14:46:52 +0000104 for (int i = 0; i < 16; ++i) {
105 dst[i] = SkMScalarToDouble(src[i]);
106 }
107#endif
108}
109
110void SkMatrix44::asRowMajorf(float dst[]) const {
111 const SkMScalar* src = &fMat[0][0];
112 for (int i = 0; i < 4; ++i) {
113 dst[0] = SkMScalarToFloat(src[0]);
114 dst[4] = SkMScalarToFloat(src[1]);
115 dst[8] = SkMScalarToFloat(src[2]);
116 dst[12] = SkMScalarToFloat(src[3]);
117 src += 4;
118 dst += 1;
119 }
120}
121
122void SkMatrix44::asRowMajord(double dst[]) const {
123 const SkMScalar* src = &fMat[0][0];
124 for (int i = 0; i < 4; ++i) {
125 dst[0] = SkMScalarToDouble(src[0]);
126 dst[4] = SkMScalarToDouble(src[1]);
127 dst[8] = SkMScalarToDouble(src[2]);
128 dst[12] = SkMScalarToDouble(src[3]);
129 src += 4;
130 dst += 1;
131 }
132}
133
vollick@chromium.orgf11cf9f2012-11-19 21:02:06 +0000134void SkMatrix44::setColMajorf(const float src[]) {
135 SkMScalar* dst = &fMat[0][0];
136#ifdef SK_MSCALAR_IS_DOUBLE
137 for (int i = 0; i < 16; ++i) {
138 dst[i] = SkMScalarToFloat(src[i]);
139 }
140#elif defined SK_MSCALAR_IS_FLOAT
141 memcpy(dst, src, 16 * sizeof(float));
142#endif
reed@google.com7d683352012-12-03 21:19:52 +0000143
144 this->dirtyTypeMask();
vollick@chromium.orgf11cf9f2012-11-19 21:02:06 +0000145}
146
147void SkMatrix44::setColMajord(const double src[]) {
148 SkMScalar* dst = &fMat[0][0];
149#ifdef SK_MSCALAR_IS_DOUBLE
150 memcpy(dst, src, 16 * sizeof(double));
151#elif defined SK_MSCALAR_IS_FLOAT
152 for (int i = 0; i < 16; ++i) {
robertphillips@google.com93f03322012-12-03 17:35:19 +0000153 dst[i] = SkDoubleToMScalar(src[i]);
vollick@chromium.orgf11cf9f2012-11-19 21:02:06 +0000154 }
155#endif
reed@google.com7d683352012-12-03 21:19:52 +0000156
157 this->dirtyTypeMask();
vollick@chromium.orgf11cf9f2012-11-19 21:02:06 +0000158}
159
160void SkMatrix44::setRowMajorf(const float src[]) {
161 SkMScalar* dst = &fMat[0][0];
162 for (int i = 0; i < 4; ++i) {
163 dst[0] = SkMScalarToFloat(src[0]);
164 dst[4] = SkMScalarToFloat(src[1]);
165 dst[8] = SkMScalarToFloat(src[2]);
166 dst[12] = SkMScalarToFloat(src[3]);
167 src += 4;
168 dst += 1;
169 }
reed@google.com7d683352012-12-03 21:19:52 +0000170 this->dirtyTypeMask();
vollick@chromium.orgf11cf9f2012-11-19 21:02:06 +0000171}
172
173void SkMatrix44::setRowMajord(const double src[]) {
174 SkMScalar* dst = &fMat[0][0];
175 for (int i = 0; i < 4; ++i) {
robertphillips@google.com93f03322012-12-03 17:35:19 +0000176 dst[0] = SkDoubleToMScalar(src[0]);
177 dst[4] = SkDoubleToMScalar(src[1]);
178 dst[8] = SkDoubleToMScalar(src[2]);
179 dst[12] = SkDoubleToMScalar(src[3]);
vollick@chromium.orgf11cf9f2012-11-19 21:02:06 +0000180 src += 4;
181 dst += 1;
182 }
reed@google.com7d683352012-12-03 21:19:52 +0000183 this->dirtyTypeMask();
vollick@chromium.orgf11cf9f2012-11-19 21:02:06 +0000184}
185
reed@google.comda9fac02011-06-13 14:46:52 +0000186///////////////////////////////////////////////////////////////////////////////
187
reed@google.com7d683352012-12-03 21:19:52 +0000188const SkMatrix44& SkMatrix44::I() {
reed@google.com1adad342012-12-10 21:21:27 +0000189 static const SkMatrix44 gIdentity44(kIdentity_Constructor);
190 return gIdentity44;
reed@google.com8260a892011-06-13 14:02:52 +0000191}
192
reed@google.com8260a892011-06-13 14:02:52 +0000193void SkMatrix44::setIdentity() {
shawnsingh@chromium.org5a6cd352013-08-28 18:55:25 +0000194 fMat[0][0] = 1;
195 fMat[0][1] = 0;
196 fMat[0][2] = 0;
197 fMat[0][3] = 0;
198 fMat[1][0] = 0;
199 fMat[1][1] = 1;
200 fMat[1][2] = 0;
201 fMat[1][3] = 0;
202 fMat[2][0] = 0;
203 fMat[2][1] = 0;
204 fMat[2][2] = 1;
205 fMat[2][3] = 0;
206 fMat[3][0] = 0;
207 fMat[3][1] = 0;
208 fMat[3][2] = 0;
209 fMat[3][3] = 1;
reed@google.com7d683352012-12-03 21:19:52 +0000210 this->setTypeMask(kIdentity_Mask);
reed@google.com8260a892011-06-13 14:02:52 +0000211}
212
213void SkMatrix44::set3x3(SkMScalar m00, SkMScalar m01, SkMScalar m02,
214 SkMScalar m10, SkMScalar m11, SkMScalar m12,
215 SkMScalar m20, SkMScalar m21, SkMScalar m22) {
reed@google.com8260a892011-06-13 14:02:52 +0000216 fMat[0][0] = m00; fMat[0][1] = m01; fMat[0][2] = m02; fMat[0][3] = 0;
217 fMat[1][0] = m10; fMat[1][1] = m11; fMat[1][2] = m12; fMat[1][3] = 0;
218 fMat[2][0] = m20; fMat[2][1] = m21; fMat[2][2] = m22; fMat[2][3] = 0;
219 fMat[3][0] = 0; fMat[3][1] = 0; fMat[3][2] = 0; fMat[3][3] = 1;
reed@google.com7d683352012-12-03 21:19:52 +0000220 this->dirtyTypeMask();
reed@google.com8260a892011-06-13 14:02:52 +0000221}
222
reed50d3b572016-05-03 12:13:21 -0700223void SkMatrix44::set3x3ColMajorf(const float src[]) {
224 fMat[0][0] = src[0]; fMat[0][1] = src[3]; fMat[0][2] = src[6]; fMat[0][3] = 0;
225 fMat[1][0] = src[1]; fMat[1][1] = src[4]; fMat[1][2] = src[7]; fMat[1][3] = 0;
226 fMat[2][0] = src[2]; fMat[2][1] = src[5]; fMat[2][2] = src[8]; fMat[2][3] = 0;
227 fMat[3][0] = 0; fMat[3][1] = 0; fMat[3][2] = 0; fMat[3][3] = 1;
228 this->dirtyTypeMask();
229}
230
msarett111a42d2016-06-22 08:18:54 -0700231void SkMatrix44::set4x3ColMajorf(const float src[]) {
232 fMat[0][0] = src[0]; fMat[0][1] = src[1]; fMat[0][2] = src[2]; fMat[0][3] = src[3];
233 fMat[1][0] = src[4]; fMat[1][1] = src[5]; fMat[1][2] = src[6]; fMat[1][3] = src[7];
234 fMat[2][0] = src[8]; fMat[2][1] = src[9]; fMat[2][2] = src[10]; fMat[2][3] = src[11];
235 fMat[3][0] = 0; fMat[3][1] = 0; fMat[3][2] = 0; fMat[3][3] = 1;
236 this->dirtyTypeMask();
237}
238
reed@google.com8260a892011-06-13 14:02:52 +0000239///////////////////////////////////////////////////////////////////////////////
240
reed@google.com99b5c7f2012-12-05 22:13:59 +0000241void SkMatrix44::setTranslate(SkMScalar dx, SkMScalar dy, SkMScalar dz) {
reed@google.com8260a892011-06-13 14:02:52 +0000242 this->setIdentity();
skia.committer@gmail.come659c2e2012-12-04 02:01:25 +0000243
reed@google.com99b5c7f2012-12-05 22:13:59 +0000244 if (!dx && !dy && !dz) {
245 return;
reed@google.com7d683352012-12-03 21:19:52 +0000246 }
skia.committer@gmail.com0264fb42012-12-06 02:01:25 +0000247
reed@google.com99b5c7f2012-12-05 22:13:59 +0000248 fMat[3][0] = dx;
249 fMat[3][1] = dy;
250 fMat[3][2] = dz;
251 this->setTypeMask(kTranslate_Mask);
reed@google.com8260a892011-06-13 14:02:52 +0000252}
253
254void SkMatrix44::preTranslate(SkMScalar dx, SkMScalar dy, SkMScalar dz) {
reed@google.com99b5c7f2012-12-05 22:13:59 +0000255 if (!dx && !dy && !dz) {
256 return;
257 }
258
reed@google.com99b5c7f2012-12-05 22:13:59 +0000259 for (int i = 0; i < 4; ++i) {
commit-bot@chromium.org658e28b2013-10-29 21:08:51 +0000260 fMat[3][i] = fMat[0][i] * dx + fMat[1][i] * dy + fMat[2][i] * dz + fMat[3][i];
reed@google.com99b5c7f2012-12-05 22:13:59 +0000261 }
262 this->dirtyTypeMask();
reed@google.com8260a892011-06-13 14:02:52 +0000263}
264
265void SkMatrix44::postTranslate(SkMScalar dx, SkMScalar dy, SkMScalar dz) {
reed@google.com99b5c7f2012-12-05 22:13:59 +0000266 if (!dx && !dy && !dz) {
267 return;
268 }
269
270 if (this->getType() & kPerspective_Mask) {
271 for (int i = 0; i < 4; ++i) {
272 fMat[i][0] += fMat[i][3] * dx;
273 fMat[i][1] += fMat[i][3] * dy;
274 fMat[i][2] += fMat[i][3] * dz;
275 }
276 } else {
277 fMat[3][0] += dx;
278 fMat[3][1] += dy;
279 fMat[3][2] += dz;
280 this->dirtyTypeMask();
281 }
reed@google.com8260a892011-06-13 14:02:52 +0000282}
283
284///////////////////////////////////////////////////////////////////////////////
285
286void SkMatrix44::setScale(SkMScalar sx, SkMScalar sy, SkMScalar sz) {
reed@google.com99b5c7f2012-12-05 22:13:59 +0000287 this->setIdentity();
288
289 if (1 == sx && 1 == sy && 1 == sz) {
290 return;
291 }
292
reed@google.com8260a892011-06-13 14:02:52 +0000293 fMat[0][0] = sx;
294 fMat[1][1] = sy;
295 fMat[2][2] = sz;
reed@google.com99b5c7f2012-12-05 22:13:59 +0000296 this->setTypeMask(kScale_Mask);
reed@google.com8260a892011-06-13 14:02:52 +0000297}
298
299void SkMatrix44::preScale(SkMScalar sx, SkMScalar sy, SkMScalar sz) {
reed@google.com99b5c7f2012-12-05 22:13:59 +0000300 if (1 == sx && 1 == sy && 1 == sz) {
301 return;
302 }
skia.committer@gmail.com0264fb42012-12-06 02:01:25 +0000303
shawnsingh@chromium.orgf81f97e2012-12-13 22:21:36 +0000304 // The implementation matrix * pureScale can be shortcut
305 // by knowing that pureScale components effectively scale
306 // the columns of the original matrix.
307 for (int i = 0; i < 4; i++) {
308 fMat[0][i] *= sx;
309 fMat[1][i] *= sy;
310 fMat[2][i] *= sz;
311 }
312 this->dirtyTypeMask();
reed@google.com8260a892011-06-13 14:02:52 +0000313}
314
315void SkMatrix44::postScale(SkMScalar sx, SkMScalar sy, SkMScalar sz) {
reed@google.com99b5c7f2012-12-05 22:13:59 +0000316 if (1 == sx && 1 == sy && 1 == sz) {
317 return;
318 }
skia.committer@gmail.com0264fb42012-12-06 02:01:25 +0000319
reed@google.com8260a892011-06-13 14:02:52 +0000320 for (int i = 0; i < 4; i++) {
321 fMat[i][0] *= sx;
322 fMat[i][1] *= sy;
323 fMat[i][2] *= sz;
324 }
reed@google.com7d683352012-12-03 21:19:52 +0000325 this->dirtyTypeMask();
reed@google.com8260a892011-06-13 14:02:52 +0000326}
327
328///////////////////////////////////////////////////////////////////////////////
329
330void SkMatrix44::setRotateAbout(SkMScalar x, SkMScalar y, SkMScalar z,
331 SkMScalar radians) {
reed@google.com7d683352012-12-03 21:19:52 +0000332 double len2 = (double)x * x + (double)y * y + (double)z * z;
333 if (1 != len2) {
334 if (0 == len2) {
reed@google.com8260a892011-06-13 14:02:52 +0000335 this->setIdentity();
336 return;
337 }
338 double scale = 1 / sqrt(len2);
bsalomon@google.com9d12f5c2011-09-29 18:08:18 +0000339 x = SkDoubleToMScalar(x * scale);
340 y = SkDoubleToMScalar(y * scale);
341 z = SkDoubleToMScalar(z * scale);
reed@google.com8260a892011-06-13 14:02:52 +0000342 }
343 this->setRotateAboutUnit(x, y, z, radians);
344}
345
346void SkMatrix44::setRotateAboutUnit(SkMScalar x, SkMScalar y, SkMScalar z,
347 SkMScalar radians) {
348 double c = cos(radians);
349 double s = sin(radians);
350 double C = 1 - c;
351 double xs = x * s;
352 double ys = y * s;
353 double zs = z * s;
354 double xC = x * C;
355 double yC = y * C;
356 double zC = z * C;
357 double xyC = x * yC;
358 double yzC = y * zC;
359 double zxC = z * xC;
360
361 // if you're looking at wikipedia, remember that we're column major.
bsalomon@google.com9d12f5c2011-09-29 18:08:18 +0000362 this->set3x3(SkDoubleToMScalar(x * xC + c), // scale x
363 SkDoubleToMScalar(xyC + zs), // skew x
364 SkDoubleToMScalar(zxC - ys), // trans x
365
366 SkDoubleToMScalar(xyC - zs), // skew y
367 SkDoubleToMScalar(y * yC + c), // scale y
368 SkDoubleToMScalar(yzC + xs), // trans y
369
370 SkDoubleToMScalar(zxC + ys), // persp x
371 SkDoubleToMScalar(yzC - xs), // persp y
372 SkDoubleToMScalar(z * zC + c)); // persp 2
reed@google.com8260a892011-06-13 14:02:52 +0000373}
374
375///////////////////////////////////////////////////////////////////////////////
376
reed@google.com99b5c7f2012-12-05 22:13:59 +0000377static bool bits_isonly(int value, int mask) {
378 return 0 == (value & ~mask);
379}
380
reed@google.com8260a892011-06-13 14:02:52 +0000381void SkMatrix44::setConcat(const SkMatrix44& a, const SkMatrix44& b) {
reed@google.com99b5c7f2012-12-05 22:13:59 +0000382 const SkMatrix44::TypeMask a_mask = a.getType();
383 const SkMatrix44::TypeMask b_mask = b.getType();
384
385 if (kIdentity_Mask == a_mask) {
reed@google.com7d683352012-12-03 21:19:52 +0000386 *this = b;
387 return;
388 }
reed@google.com99b5c7f2012-12-05 22:13:59 +0000389 if (kIdentity_Mask == b_mask) {
reed@google.com7d683352012-12-03 21:19:52 +0000390 *this = a;
391 return;
392 }
393
394 bool useStorage = (this == &a || this == &b);
395 SkMScalar storage[16];
396 SkMScalar* result = useStorage ? storage : &fMat[0][0];
397
reed@google.com2b165702013-01-17 16:01:19 +0000398 // Both matrices are at most scale+translate
reed@google.com99b5c7f2012-12-05 22:13:59 +0000399 if (bits_isonly(a_mask | b_mask, kScale_Mask | kTranslate_Mask)) {
reed@google.com99b5c7f2012-12-05 22:13:59 +0000400 result[0] = a.fMat[0][0] * b.fMat[0][0];
reed@google.com2b165702013-01-17 16:01:19 +0000401 result[1] = result[2] = result[3] = result[4] = 0;
reed@google.com99b5c7f2012-12-05 22:13:59 +0000402 result[5] = a.fMat[1][1] * b.fMat[1][1];
reed@google.com2b165702013-01-17 16:01:19 +0000403 result[6] = result[7] = result[8] = result[9] = 0;
reed@google.com99b5c7f2012-12-05 22:13:59 +0000404 result[10] = a.fMat[2][2] * b.fMat[2][2];
reed@google.com2b165702013-01-17 16:01:19 +0000405 result[11] = 0;
reed@google.com99b5c7f2012-12-05 22:13:59 +0000406 result[12] = a.fMat[0][0] * b.fMat[3][0] + a.fMat[3][0];
407 result[13] = a.fMat[1][1] * b.fMat[3][1] + a.fMat[3][1];
408 result[14] = a.fMat[2][2] * b.fMat[3][2] + a.fMat[3][2];
409 result[15] = 1;
410 } else {
411 for (int j = 0; j < 4; j++) {
412 for (int i = 0; i < 4; i++) {
commit-bot@chromium.orgbde4ba22014-01-24 18:48:00 +0000413 double value = 0;
reed@google.com99b5c7f2012-12-05 22:13:59 +0000414 for (int k = 0; k < 4; k++) {
commit-bot@chromium.orgbde4ba22014-01-24 18:48:00 +0000415 value += SkMScalarToDouble(a.fMat[k][i]) * b.fMat[j][k];
reed@google.com99b5c7f2012-12-05 22:13:59 +0000416 }
commit-bot@chromium.orgbde4ba22014-01-24 18:48:00 +0000417 *result++ = SkDoubleToMScalar(value);
reed@google.com8260a892011-06-13 14:02:52 +0000418 }
reed@google.com8260a892011-06-13 14:02:52 +0000419 }
420 }
reed@google.com99b5c7f2012-12-05 22:13:59 +0000421
reed@google.com7d683352012-12-03 21:19:52 +0000422 if (useStorage) {
tomhudson@google.com7cfb9c72013-01-17 13:29:35 +0000423 memcpy(fMat, storage, sizeof(storage));
reed@google.com7d683352012-12-03 21:19:52 +0000424 }
reed@google.com7d683352012-12-03 21:19:52 +0000425 this->dirtyTypeMask();
reed@google.com8260a892011-06-13 14:02:52 +0000426}
427
428///////////////////////////////////////////////////////////////////////////////
429
reed@google.com8260a892011-06-13 14:02:52 +0000430/** We always perform the calculation in doubles, to avoid prematurely losing
431 precision along the way. This relies on the compiler automatically
432 promoting our SkMScalar values to double (if needed).
433 */
434double SkMatrix44::determinant() const {
mike@reedtribe.orgf8b1ebc2012-12-10 03:27:47 +0000435 if (this->isIdentity()) {
436 return 1;
437 }
438 if (this->isScaleTranslate()) {
439 return fMat[0][0] * fMat[1][1] * fMat[2][2] * fMat[3][3];
440 }
441
tomhudson@google.com9973a8a2012-12-13 09:55:42 +0000442 double a00 = fMat[0][0];
443 double a01 = fMat[0][1];
444 double a02 = fMat[0][2];
445 double a03 = fMat[0][3];
446 double a10 = fMat[1][0];
447 double a11 = fMat[1][1];
448 double a12 = fMat[1][2];
449 double a13 = fMat[1][3];
450 double a20 = fMat[2][0];
451 double a21 = fMat[2][1];
452 double a22 = fMat[2][2];
453 double a23 = fMat[2][3];
454 double a30 = fMat[3][0];
455 double a31 = fMat[3][1];
456 double a32 = fMat[3][2];
457 double a33 = fMat[3][3];
458
459 double b00 = a00 * a11 - a01 * a10;
460 double b01 = a00 * a12 - a02 * a10;
461 double b02 = a00 * a13 - a03 * a10;
462 double b03 = a01 * a12 - a02 * a11;
463 double b04 = a01 * a13 - a03 * a11;
464 double b05 = a02 * a13 - a03 * a12;
465 double b06 = a20 * a31 - a21 * a30;
466 double b07 = a20 * a32 - a22 * a30;
467 double b08 = a20 * a33 - a23 * a30;
468 double b09 = a21 * a32 - a22 * a31;
469 double b10 = a21 * a33 - a23 * a31;
470 double b11 = a22 * a33 - a23 * a32;
471
472 // Calculate the determinant
473 return b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
reed@google.com8260a892011-06-13 14:02:52 +0000474}
475
476///////////////////////////////////////////////////////////////////////////////
477
vmpstra8d45592015-06-30 13:36:04 -0700478static bool is_matrix_finite(const SkMatrix44& matrix) {
479 SkMScalar accumulator = 0;
480 for (int row = 0; row < 4; ++row) {
481 for (int col = 0; col < 4; ++col) {
482 accumulator *= matrix.get(row, col);
483 }
484 }
485 return accumulator == 0;
486}
487
488bool SkMatrix44::invert(SkMatrix44* storage) const {
mike@reedtribe.orgf8b1ebc2012-12-10 03:27:47 +0000489 if (this->isIdentity()) {
vmpstra8d45592015-06-30 13:36:04 -0700490 if (storage) {
491 storage->setIdentity();
reed@google.com7d683352012-12-03 21:19:52 +0000492 }
commit-bot@chromium.org178acd22013-11-20 21:32:27 +0000493 return true;
reed@google.com7d683352012-12-03 21:19:52 +0000494 }
commit-bot@chromium.org178acd22013-11-20 21:32:27 +0000495
mike@reedtribe.orgf8b1ebc2012-12-10 03:27:47 +0000496 if (this->isTranslate()) {
vmpstra8d45592015-06-30 13:36:04 -0700497 if (storage) {
498 storage->setTranslate(-fMat[3][0], -fMat[3][1], -fMat[3][2]);
reed@google.com99b5c7f2012-12-05 22:13:59 +0000499 }
500 return true;
501 }
commit-bot@chromium.org178acd22013-11-20 21:32:27 +0000502
vmpstra8d45592015-06-30 13:36:04 -0700503 SkMatrix44 tmp(kUninitialized_Constructor);
504 // Use storage if it's available and distinct from this matrix.
505 SkMatrix44* inverse = (storage && storage != this) ? storage : &tmp;
mike@reedtribe.orgf8b1ebc2012-12-10 03:27:47 +0000506 if (this->isScaleTranslate()) {
reed@google.com99b5c7f2012-12-05 22:13:59 +0000507 if (0 == fMat[0][0] * fMat[1][1] * fMat[2][2]) {
508 return false;
509 }
reed@google.com99b5c7f2012-12-05 22:13:59 +0000510
vmpstra8d45592015-06-30 13:36:04 -0700511 double invXScale = 1 / fMat[0][0];
512 double invYScale = 1 / fMat[1][1];
513 double invZScale = 1 / fMat[2][2];
reed@google.com99b5c7f2012-12-05 22:13:59 +0000514
vmpstra8d45592015-06-30 13:36:04 -0700515 inverse->fMat[0][0] = SkDoubleToMScalar(invXScale);
516 inverse->fMat[0][1] = 0;
517 inverse->fMat[0][2] = 0;
518 inverse->fMat[0][3] = 0;
skia.committer@gmail.com772c4e62013-08-30 07:01:34 +0000519
vmpstra8d45592015-06-30 13:36:04 -0700520 inverse->fMat[1][0] = 0;
521 inverse->fMat[1][1] = SkDoubleToMScalar(invYScale);
522 inverse->fMat[1][2] = 0;
523 inverse->fMat[1][3] = 0;
skia.committer@gmail.com772c4e62013-08-30 07:01:34 +0000524
vmpstra8d45592015-06-30 13:36:04 -0700525 inverse->fMat[2][0] = 0;
526 inverse->fMat[2][1] = 0;
527 inverse->fMat[2][2] = SkDoubleToMScalar(invZScale);
528 inverse->fMat[2][3] = 0;
skia.committer@gmail.com772c4e62013-08-30 07:01:34 +0000529
vmpstra8d45592015-06-30 13:36:04 -0700530 inverse->fMat[3][0] = SkDoubleToMScalar(-fMat[3][0] * invXScale);
531 inverse->fMat[3][1] = SkDoubleToMScalar(-fMat[3][1] * invYScale);
532 inverse->fMat[3][2] = SkDoubleToMScalar(-fMat[3][2] * invZScale);
533 inverse->fMat[3][3] = 1;
shawnsingh@chromium.orgb6823c12013-08-22 20:24:21 +0000534
vmpstra8d45592015-06-30 13:36:04 -0700535 inverse->setTypeMask(this->getType());
536
537 if (!is_matrix_finite(*inverse)) {
538 return false;
shawnsingh@chromium.org5a6cd352013-08-28 18:55:25 +0000539 }
vmpstra8d45592015-06-30 13:36:04 -0700540 if (storage && inverse != storage) {
541 *storage = *inverse;
542 }
reed@google.com99b5c7f2012-12-05 22:13:59 +0000543 return true;
544 }
545
tomhudson@google.com9973a8a2012-12-13 09:55:42 +0000546 double a00 = fMat[0][0];
547 double a01 = fMat[0][1];
548 double a02 = fMat[0][2];
549 double a03 = fMat[0][3];
550 double a10 = fMat[1][0];
551 double a11 = fMat[1][1];
552 double a12 = fMat[1][2];
553 double a13 = fMat[1][3];
554 double a20 = fMat[2][0];
555 double a21 = fMat[2][1];
556 double a22 = fMat[2][2];
557 double a23 = fMat[2][3];
558 double a30 = fMat[3][0];
559 double a31 = fMat[3][1];
560 double a32 = fMat[3][2];
561 double a33 = fMat[3][3];
562
shawnsingh@chromium.orgb6823c12013-08-22 20:24:21 +0000563 if (!(this->getType() & kPerspective_Mask)) {
564 // If we know the matrix has no perspective, then the perspective
565 // component is (0, 0, 0, 1). We can use this information to save a lot
566 // of arithmetic that would otherwise be spent to compute the inverse
567 // of a general matrix.
568
569 SkASSERT(a03 == 0);
570 SkASSERT(a13 == 0);
571 SkASSERT(a23 == 0);
572 SkASSERT(a33 == 1);
573
574 double b00 = a00 * a11 - a01 * a10;
575 double b01 = a00 * a12 - a02 * a10;
576 double b03 = a01 * a12 - a02 * a11;
577 double b06 = a20 * a31 - a21 * a30;
578 double b07 = a20 * a32 - a22 * a30;
579 double b08 = a20;
580 double b09 = a21 * a32 - a22 * a31;
581 double b10 = a21;
582 double b11 = a22;
583
584 // Calculate the determinant
585 double det = b00 * b11 - b01 * b10 + b03 * b08;
586
587 double invdet = 1.0 / det;
588 // If det is zero, we want to return false. However, we also want to return false
589 // if 1/det overflows to infinity (i.e. det is denormalized). Both of these are
590 // handled by checking that 1/det is finite.
591 if (!sk_float_isfinite(invdet)) {
592 return false;
593 }
shawnsingh@chromium.orgb6823c12013-08-22 20:24:21 +0000594
595 b00 *= invdet;
596 b01 *= invdet;
597 b03 *= invdet;
598 b06 *= invdet;
599 b07 *= invdet;
600 b08 *= invdet;
601 b09 *= invdet;
602 b10 *= invdet;
603 b11 *= invdet;
604
605 inverse->fMat[0][0] = SkDoubleToMScalar(a11 * b11 - a12 * b10);
606 inverse->fMat[0][1] = SkDoubleToMScalar(a02 * b10 - a01 * b11);
607 inverse->fMat[0][2] = SkDoubleToMScalar(b03);
608 inverse->fMat[0][3] = 0;
609 inverse->fMat[1][0] = SkDoubleToMScalar(a12 * b08 - a10 * b11);
610 inverse->fMat[1][1] = SkDoubleToMScalar(a00 * b11 - a02 * b08);
611 inverse->fMat[1][2] = SkDoubleToMScalar(-b01);
612 inverse->fMat[1][3] = 0;
613 inverse->fMat[2][0] = SkDoubleToMScalar(a10 * b10 - a11 * b08);
614 inverse->fMat[2][1] = SkDoubleToMScalar(a01 * b08 - a00 * b10);
615 inverse->fMat[2][2] = SkDoubleToMScalar(b00);
616 inverse->fMat[2][3] = 0;
617 inverse->fMat[3][0] = SkDoubleToMScalar(a11 * b07 - a10 * b09 - a12 * b06);
618 inverse->fMat[3][1] = SkDoubleToMScalar(a00 * b09 - a01 * b07 + a02 * b06);
619 inverse->fMat[3][2] = SkDoubleToMScalar(a31 * b01 - a30 * b03 - a32 * b00);
620 inverse->fMat[3][3] = 1;
621
622 inverse->setTypeMask(this->getType());
vmpstra8d45592015-06-30 13:36:04 -0700623 if (!is_matrix_finite(*inverse)) {
624 return false;
625 }
626 if (storage && inverse != storage) {
627 *storage = *inverse;
628 }
shawnsingh@chromium.orgb6823c12013-08-22 20:24:21 +0000629 return true;
630 }
631
tomhudson@google.com9973a8a2012-12-13 09:55:42 +0000632 double b00 = a00 * a11 - a01 * a10;
633 double b01 = a00 * a12 - a02 * a10;
634 double b02 = a00 * a13 - a03 * a10;
635 double b03 = a01 * a12 - a02 * a11;
636 double b04 = a01 * a13 - a03 * a11;
637 double b05 = a02 * a13 - a03 * a12;
638 double b06 = a20 * a31 - a21 * a30;
639 double b07 = a20 * a32 - a22 * a30;
640 double b08 = a20 * a33 - a23 * a30;
641 double b09 = a21 * a32 - a22 * a31;
642 double b10 = a21 * a33 - a23 * a31;
643 double b11 = a22 * a33 - a23 * a32;
644
645 // Calculate the determinant
646 double det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
647
commit-bot@chromium.orgf02f0782013-08-20 15:25:04 +0000648 double invdet = 1.0 / det;
649 // If det is zero, we want to return false. However, we also want to return false
650 // if 1/det overflows to infinity (i.e. det is denormalized). Both of these are
651 // handled by checking that 1/det is finite.
652 if (!sk_float_isfinite(invdet)) {
reed@google.com8260a892011-06-13 14:02:52 +0000653 return false;
654 }
reed@google.com8260a892011-06-13 14:02:52 +0000655
tomhudson@google.com9973a8a2012-12-13 09:55:42 +0000656 b00 *= invdet;
657 b01 *= invdet;
658 b02 *= invdet;
659 b03 *= invdet;
660 b04 *= invdet;
661 b05 *= invdet;
662 b06 *= invdet;
663 b07 *= invdet;
664 b08 *= invdet;
665 b09 *= invdet;
666 b10 *= invdet;
667 b11 *= invdet;
reed@google.com8260a892011-06-13 14:02:52 +0000668
tomhudson@google.com9973a8a2012-12-13 09:55:42 +0000669 inverse->fMat[0][0] = SkDoubleToMScalar(a11 * b11 - a12 * b10 + a13 * b09);
670 inverse->fMat[0][1] = SkDoubleToMScalar(a02 * b10 - a01 * b11 - a03 * b09);
671 inverse->fMat[0][2] = SkDoubleToMScalar(a31 * b05 - a32 * b04 + a33 * b03);
672 inverse->fMat[0][3] = SkDoubleToMScalar(a22 * b04 - a21 * b05 - a23 * b03);
673 inverse->fMat[1][0] = SkDoubleToMScalar(a12 * b08 - a10 * b11 - a13 * b07);
674 inverse->fMat[1][1] = SkDoubleToMScalar(a00 * b11 - a02 * b08 + a03 * b07);
675 inverse->fMat[1][2] = SkDoubleToMScalar(a32 * b02 - a30 * b05 - a33 * b01);
676 inverse->fMat[1][3] = SkDoubleToMScalar(a20 * b05 - a22 * b02 + a23 * b01);
677 inverse->fMat[2][0] = SkDoubleToMScalar(a10 * b10 - a11 * b08 + a13 * b06);
678 inverse->fMat[2][1] = SkDoubleToMScalar(a01 * b08 - a00 * b10 - a03 * b06);
679 inverse->fMat[2][2] = SkDoubleToMScalar(a30 * b04 - a31 * b02 + a33 * b00);
680 inverse->fMat[2][3] = SkDoubleToMScalar(a21 * b02 - a20 * b04 - a23 * b00);
681 inverse->fMat[3][0] = SkDoubleToMScalar(a11 * b07 - a10 * b09 - a12 * b06);
682 inverse->fMat[3][1] = SkDoubleToMScalar(a00 * b09 - a01 * b07 + a02 * b06);
683 inverse->fMat[3][2] = SkDoubleToMScalar(a31 * b01 - a30 * b03 - a32 * b00);
684 inverse->fMat[3][3] = SkDoubleToMScalar(a20 * b03 - a21 * b01 + a22 * b00);
685 inverse->dirtyTypeMask();
reed@google.com8260a892011-06-13 14:02:52 +0000686
vmpstra8d45592015-06-30 13:36:04 -0700687 inverse->setTypeMask(this->getType());
688 if (!is_matrix_finite(*inverse)) {
689 return false;
690 }
691 if (storage && inverse != storage) {
692 *storage = *inverse;
693 }
reed@google.com8260a892011-06-13 14:02:52 +0000694 return true;
695}
696
697///////////////////////////////////////////////////////////////////////////////
698
vollick@chromium.org9b21c252012-11-14 21:33:55 +0000699void SkMatrix44::transpose() {
700 SkTSwap(fMat[0][1], fMat[1][0]);
701 SkTSwap(fMat[0][2], fMat[2][0]);
702 SkTSwap(fMat[0][3], fMat[3][0]);
703 SkTSwap(fMat[1][2], fMat[2][1]);
704 SkTSwap(fMat[1][3], fMat[3][1]);
705 SkTSwap(fMat[2][3], fMat[3][2]);
reed@google.com7d683352012-12-03 21:19:52 +0000706
707 if (!this->isTriviallyIdentity()) {
708 this->dirtyTypeMask();
709 }
vollick@chromium.org9b21c252012-11-14 21:33:55 +0000710}
711
712///////////////////////////////////////////////////////////////////////////////
713
reed@google.com1ea95be2012-11-09 21:39:48 +0000714void SkMatrix44::mapScalars(const SkScalar src[4], SkScalar dst[4]) const {
reed@google.com7d683352012-12-03 21:19:52 +0000715 SkScalar storage[4];
716 SkScalar* result = (src == dst) ? storage : dst;
717
reed@google.com8260a892011-06-13 14:02:52 +0000718 for (int i = 0; i < 4; i++) {
719 SkMScalar value = 0;
720 for (int j = 0; j < 4; j++) {
721 value += fMat[j][i] * src[j];
722 }
bsalomon@google.com72e49b82011-10-27 21:47:03 +0000723 result[i] = SkMScalarToScalar(value);
reed@google.com8260a892011-06-13 14:02:52 +0000724 }
skia.committer@gmail.com0264fb42012-12-06 02:01:25 +0000725
reed@google.com7d683352012-12-03 21:19:52 +0000726 if (storage == result) {
727 memcpy(dst, storage, sizeof(storage));
728 }
reed@google.com8260a892011-06-13 14:02:52 +0000729}
730
reed@google.com1ea95be2012-11-09 21:39:48 +0000731#ifdef SK_MSCALAR_IS_DOUBLE
reed@google.com7d683352012-12-03 21:19:52 +0000732
reed@google.com1ea95be2012-11-09 21:39:48 +0000733void SkMatrix44::mapMScalars(const SkMScalar src[4], SkMScalar dst[4]) const {
reed@google.com7d683352012-12-03 21:19:52 +0000734 SkMScalar storage[4];
735 SkMScalar* result = (src == dst) ? storage : dst;
skia.committer@gmail.com0264fb42012-12-06 02:01:25 +0000736
reed@google.com1ea95be2012-11-09 21:39:48 +0000737 for (int i = 0; i < 4; i++) {
738 SkMScalar value = 0;
739 for (int j = 0; j < 4; j++) {
740 value += fMat[j][i] * src[j];
741 }
reed@google.com7d683352012-12-03 21:19:52 +0000742 result[i] = value;
reed@google.com1ea95be2012-11-09 21:39:48 +0000743 }
skia.committer@gmail.com0264fb42012-12-06 02:01:25 +0000744
reed@google.com7d683352012-12-03 21:19:52 +0000745 if (storage == result) {
746 memcpy(dst, storage, sizeof(storage));
747 }
reed@google.com1ea95be2012-11-09 21:39:48 +0000748}
reed@google.com7d683352012-12-03 21:19:52 +0000749
reed@google.com1ea95be2012-11-09 21:39:48 +0000750#endif
751
reed@google.com99b5c7f2012-12-05 22:13:59 +0000752typedef void (*Map2Procf)(const SkMScalar mat[][4], const float src2[], int count, float dst4[]);
753typedef void (*Map2Procd)(const SkMScalar mat[][4], const double src2[], int count, double dst4[]);
754
755static void map2_if(const SkMScalar mat[][4], const float* SK_RESTRICT src2,
756 int count, float* SK_RESTRICT dst4) {
757 for (int i = 0; i < count; ++i) {
758 dst4[0] = src2[0];
759 dst4[1] = src2[1];
760 dst4[2] = 0;
761 dst4[3] = 1;
762 src2 += 2;
763 dst4 += 4;
764 }
765}
766
767static void map2_id(const SkMScalar mat[][4], const double* SK_RESTRICT src2,
768 int count, double* SK_RESTRICT dst4) {
769 for (int i = 0; i < count; ++i) {
770 dst4[0] = src2[0];
771 dst4[1] = src2[1];
772 dst4[2] = 0;
773 dst4[3] = 1;
774 src2 += 2;
775 dst4 += 4;
776 }
777}
778
779static void map2_tf(const SkMScalar mat[][4], const float* SK_RESTRICT src2,
780 int count, float* SK_RESTRICT dst4) {
781 const float mat30 = SkMScalarToFloat(mat[3][0]);
782 const float mat31 = SkMScalarToFloat(mat[3][1]);
783 const float mat32 = SkMScalarToFloat(mat[3][2]);
784 for (int n = 0; n < count; ++n) {
785 dst4[0] = src2[0] + mat30;
786 dst4[1] = src2[1] + mat31;
787 dst4[2] = mat32;
788 dst4[3] = 1;
789 src2 += 2;
790 dst4 += 4;
791 }
792}
793
794static void map2_td(const SkMScalar mat[][4], const double* SK_RESTRICT src2,
795 int count, double* SK_RESTRICT dst4) {
796 for (int n = 0; n < count; ++n) {
797 dst4[0] = src2[0] + mat[3][0];
798 dst4[1] = src2[1] + mat[3][1];
799 dst4[2] = mat[3][2];
800 dst4[3] = 1;
801 src2 += 2;
802 dst4 += 4;
803 }
804}
805
806static void map2_sf(const SkMScalar mat[][4], const float* SK_RESTRICT src2,
807 int count, float* SK_RESTRICT dst4) {
808 const float mat32 = SkMScalarToFloat(mat[3][2]);
809 for (int n = 0; n < count; ++n) {
810 dst4[0] = SkMScalarToFloat(mat[0][0] * src2[0] + mat[3][0]);
811 dst4[1] = SkMScalarToFloat(mat[1][1] * src2[1] + mat[3][1]);
812 dst4[2] = mat32;
813 dst4[3] = 1;
814 src2 += 2;
815 dst4 += 4;
816 }
817}
818
819static void map2_sd(const SkMScalar mat[][4], const double* SK_RESTRICT src2,
820 int count, double* SK_RESTRICT dst4) {
821 for (int n = 0; n < count; ++n) {
822 dst4[0] = mat[0][0] * src2[0] + mat[3][0];
823 dst4[1] = mat[1][1] * src2[1] + mat[3][1];
824 dst4[2] = mat[3][2];
825 dst4[3] = 1;
826 src2 += 2;
827 dst4 += 4;
828 }
829}
830
831static void map2_af(const SkMScalar mat[][4], const float* SK_RESTRICT src2,
832 int count, float* SK_RESTRICT dst4) {
commit-bot@chromium.org658e28b2013-10-29 21:08:51 +0000833 SkMScalar r;
reed@google.com99b5c7f2012-12-05 22:13:59 +0000834 for (int n = 0; n < count; ++n) {
commit-bot@chromium.org658e28b2013-10-29 21:08:51 +0000835 SkMScalar sx = SkFloatToMScalar(src2[0]);
836 SkMScalar sy = SkFloatToMScalar(src2[1]);
reed@google.com99b5c7f2012-12-05 22:13:59 +0000837 r = mat[0][0] * sx + mat[1][0] * sy + mat[3][0];
838 dst4[0] = SkMScalarToFloat(r);
839 r = mat[0][1] * sx + mat[1][1] * sy + mat[3][1];
840 dst4[1] = SkMScalarToFloat(r);
841 r = mat[0][2] * sx + mat[1][2] * sy + mat[3][2];
842 dst4[2] = SkMScalarToFloat(r);
843 dst4[3] = 1;
844 src2 += 2;
845 dst4 += 4;
846 }
847}
848
849static void map2_ad(const SkMScalar mat[][4], const double* SK_RESTRICT src2,
850 int count, double* SK_RESTRICT dst4) {
851 for (int n = 0; n < count; ++n) {
852 double sx = src2[0];
853 double sy = src2[1];
854 dst4[0] = mat[0][0] * sx + mat[1][0] * sy + mat[3][0];
855 dst4[1] = mat[0][1] * sx + mat[1][1] * sy + mat[3][1];
856 dst4[2] = mat[0][2] * sx + mat[1][2] * sy + mat[3][2];
857 dst4[3] = 1;
858 src2 += 2;
859 dst4 += 4;
860 }
861}
862
863static void map2_pf(const SkMScalar mat[][4], const float* SK_RESTRICT src2,
864 int count, float* SK_RESTRICT dst4) {
commit-bot@chromium.org658e28b2013-10-29 21:08:51 +0000865 SkMScalar r;
reed@google.com99b5c7f2012-12-05 22:13:59 +0000866 for (int n = 0; n < count; ++n) {
commit-bot@chromium.org658e28b2013-10-29 21:08:51 +0000867 SkMScalar sx = SkFloatToMScalar(src2[0]);
868 SkMScalar sy = SkFloatToMScalar(src2[1]);
reed@google.com99b5c7f2012-12-05 22:13:59 +0000869 for (int i = 0; i < 4; i++) {
commit-bot@chromium.org658e28b2013-10-29 21:08:51 +0000870 r = mat[0][i] * sx + mat[1][i] * sy + mat[3][i];
871 dst4[i] = SkMScalarToFloat(r);
reed@google.com99b5c7f2012-12-05 22:13:59 +0000872 }
873 src2 += 2;
874 dst4 += 4;
875 }
876}
877
878static void map2_pd(const SkMScalar mat[][4], const double* SK_RESTRICT src2,
879 int count, double* SK_RESTRICT dst4) {
880 for (int n = 0; n < count; ++n) {
881 double sx = src2[0];
882 double sy = src2[1];
883 for (int i = 0; i < 4; i++) {
884 dst4[i] = mat[0][i] * sx + mat[1][i] * sy + mat[3][i];
885 }
886 src2 += 2;
887 dst4 += 4;
888 }
889}
890
891void SkMatrix44::map2(const float src2[], int count, float dst4[]) const {
892 static const Map2Procf gProc[] = {
893 map2_if, map2_tf, map2_sf, map2_sf, map2_af, map2_af, map2_af, map2_af
894 };
895
896 TypeMask mask = this->getType();
897 Map2Procf proc = (mask & kPerspective_Mask) ? map2_pf : gProc[mask];
898 proc(fMat, src2, count, dst4);
899}
900
901void SkMatrix44::map2(const double src2[], int count, double dst4[]) const {
902 static const Map2Procd gProc[] = {
903 map2_id, map2_td, map2_sd, map2_sd, map2_ad, map2_ad, map2_ad, map2_ad
904 };
skia.committer@gmail.com0264fb42012-12-06 02:01:25 +0000905
reed@google.com99b5c7f2012-12-05 22:13:59 +0000906 TypeMask mask = this->getType();
907 Map2Procd proc = (mask & kPerspective_Mask) ? map2_pd : gProc[mask];
908 proc(fMat, src2, count, dst4);
909}
910
tomhudsonfaccb8e2014-09-26 11:45:48 -0700911bool SkMatrix44::preserves2dAxisAlignment (SkMScalar epsilon) const {
912
913 // Can't check (mask & kPerspective_Mask) because Z isn't relevant here.
914 if (0 != perspX() || 0 != perspY()) return false;
915
916 // A matrix with two non-zeroish values in any of the upper right
917 // rows or columns will skew. If only one value in each row or
918 // column is non-zeroish, we get a scale plus perhaps a 90-degree
919 // rotation.
920 int col0 = 0;
921 int col1 = 0;
922 int row0 = 0;
923 int row1 = 0;
924
925 // Must test against epsilon, not 0, because we can get values
926 // around 6e-17 in the matrix that "should" be 0.
927
928 if (SkMScalarAbs(fMat[0][0]) > epsilon) {
929 col0++;
930 row0++;
931 }
932 if (SkMScalarAbs(fMat[0][1]) > epsilon) {
933 col1++;
934 row0++;
935 }
936 if (SkMScalarAbs(fMat[1][0]) > epsilon) {
937 col0++;
938 row1++;
939 }
940 if (SkMScalarAbs(fMat[1][1]) > epsilon) {
941 col1++;
942 row1++;
943 }
944 if (col0 > 1 || col1 > 1 || row0 > 1 || row1 > 1) {
945 return false;
946 }
947
948 return true;
949}
950
reed@google.com8260a892011-06-13 14:02:52 +0000951///////////////////////////////////////////////////////////////////////////////
952
953void SkMatrix44::dump() const {
tomhudson@google.com9ac4a892011-06-28 13:53:13 +0000954 static const char* format =
955 "[%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 +0000956#if 0
tomhudson@google.com9ac4a892011-06-28 13:53:13 +0000957 SkDebugf(format,
reed@google.com8260a892011-06-13 14:02:52 +0000958 fMat[0][0], fMat[1][0], fMat[2][0], fMat[3][0],
959 fMat[0][1], fMat[1][1], fMat[2][1], fMat[3][1],
960 fMat[0][2], fMat[1][2], fMat[2][2], fMat[3][2],
961 fMat[0][3], fMat[1][3], fMat[2][3], fMat[3][3]);
tomhudson@google.com9ac4a892011-06-28 13:53:13 +0000962#else
963 SkDebugf(format,
964 fMat[0][0], fMat[0][1], fMat[0][2], fMat[0][3],
965 fMat[1][0], fMat[1][1], fMat[1][2], fMat[1][3],
966 fMat[2][0], fMat[2][1], fMat[2][2], fMat[2][3],
967 fMat[3][0], fMat[3][1], fMat[3][2], fMat[3][3]);
reed@google.com8260a892011-06-13 14:02:52 +0000968#endif
969}
970
971///////////////////////////////////////////////////////////////////////////////
972
973static void initFromMatrix(SkMScalar dst[4][4], const SkMatrix& src) {
bsalomon@google.com72e49b82011-10-27 21:47:03 +0000974 dst[0][0] = SkScalarToMScalar(src[SkMatrix::kMScaleX]);
975 dst[1][0] = SkScalarToMScalar(src[SkMatrix::kMSkewX]);
shawnsingh@chromium.org5a6cd352013-08-28 18:55:25 +0000976 dst[2][0] = 0;
bsalomon@google.com72e49b82011-10-27 21:47:03 +0000977 dst[3][0] = SkScalarToMScalar(src[SkMatrix::kMTransX]);
978 dst[0][1] = SkScalarToMScalar(src[SkMatrix::kMSkewY]);
979 dst[1][1] = SkScalarToMScalar(src[SkMatrix::kMScaleY]);
shawnsingh@chromium.org5a6cd352013-08-28 18:55:25 +0000980 dst[2][1] = 0;
bsalomon@google.com72e49b82011-10-27 21:47:03 +0000981 dst[3][1] = SkScalarToMScalar(src[SkMatrix::kMTransY]);
shawnsingh@chromium.org5a6cd352013-08-28 18:55:25 +0000982 dst[0][2] = 0;
983 dst[1][2] = 0;
984 dst[2][2] = 1;
985 dst[3][2] = 0;
commit-bot@chromium.org722555b2013-10-05 01:16:30 +0000986 dst[0][3] = SkScalarToMScalar(src[SkMatrix::kMPersp0]);
987 dst[1][3] = SkScalarToMScalar(src[SkMatrix::kMPersp1]);
shawnsingh@chromium.org5a6cd352013-08-28 18:55:25 +0000988 dst[2][3] = 0;
commit-bot@chromium.org722555b2013-10-05 01:16:30 +0000989 dst[3][3] = SkScalarToMScalar(src[SkMatrix::kMPersp2]);
reed@google.com8260a892011-06-13 14:02:52 +0000990}
991
992SkMatrix44::SkMatrix44(const SkMatrix& src) {
fs88640cf2014-12-16 08:36:11 -0800993 this->operator=(src);
reed@google.com8260a892011-06-13 14:02:52 +0000994}
995
996SkMatrix44& SkMatrix44::operator=(const SkMatrix& src) {
997 initFromMatrix(fMat, src);
reed@google.com7d683352012-12-03 21:19:52 +0000998
999 if (src.isIdentity()) {
1000 this->setTypeMask(kIdentity_Mask);
1001 } else {
1002 this->dirtyTypeMask();
1003 }
reed@google.com8260a892011-06-13 14:02:52 +00001004 return *this;
1005}
1006
1007SkMatrix44::operator SkMatrix() const {
1008 SkMatrix dst;
reed@google.com8260a892011-06-13 14:02:52 +00001009
bsalomon@google.com72e49b82011-10-27 21:47:03 +00001010 dst[SkMatrix::kMScaleX] = SkMScalarToScalar(fMat[0][0]);
1011 dst[SkMatrix::kMSkewX] = SkMScalarToScalar(fMat[1][0]);
1012 dst[SkMatrix::kMTransX] = SkMScalarToScalar(fMat[3][0]);
reed@google.com8260a892011-06-13 14:02:52 +00001013
bsalomon@google.com72e49b82011-10-27 21:47:03 +00001014 dst[SkMatrix::kMSkewY] = SkMScalarToScalar(fMat[0][1]);
1015 dst[SkMatrix::kMScaleY] = SkMScalarToScalar(fMat[1][1]);
1016 dst[SkMatrix::kMTransY] = SkMScalarToScalar(fMat[3][1]);
reed@google.com8260a892011-06-13 14:02:52 +00001017
commit-bot@chromium.org722555b2013-10-05 01:16:30 +00001018 dst[SkMatrix::kMPersp0] = SkMScalarToScalar(fMat[0][3]);
1019 dst[SkMatrix::kMPersp1] = SkMScalarToScalar(fMat[1][3]);
1020 dst[SkMatrix::kMPersp2] = SkMScalarToScalar(fMat[3][3]);
1021
reed@google.com8260a892011-06-13 14:02:52 +00001022 return dst;
1023}