blob: 1b089879fed71bb22f552b79d873304ba4eccde0 [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"
Ben Wagnerf08d1d02018-06-18 15:11:00 -04009#include <utility>
reed@google.com8260a892011-06-13 14:02:52 +000010
reed@google.com7d683352012-12-03 21:19:52 +000011static inline bool eq4(const SkMScalar* SK_RESTRICT a,
12 const SkMScalar* SK_RESTRICT b) {
13 return (a[0] == b[0]) & (a[1] == b[1]) & (a[2] == b[2]) & (a[3] == b[3]);
14}
jamesr@chromium.orgdeb4c162012-11-29 21:17:16 +000015
reed@google.com7d683352012-12-03 21:19:52 +000016bool SkMatrix44::operator==(const SkMatrix44& other) const {
17 if (this == &other) {
18 return true;
19 }
20
21 if (this->isTriviallyIdentity() && other.isTriviallyIdentity()) {
22 return true;
23 }
24
25 const SkMScalar* SK_RESTRICT a = &fMat[0][0];
26 const SkMScalar* SK_RESTRICT b = &other.fMat[0][0];
27
28#if 0
reed@google.com631940c2012-11-27 13:13:22 +000029 for (int i = 0; i < 16; ++i) {
30 if (a[i] != b[i]) {
31 return false;
32 }
33 }
34 return true;
reed@google.com7d683352012-12-03 21:19:52 +000035#else
36 // to reduce branch instructions, we compare 4 at a time.
37 // see bench/Matrix44Bench.cpp for test.
38 if (!eq4(&a[0], &b[0])) {
39 return false;
40 }
41 if (!eq4(&a[4], &b[4])) {
42 return false;
43 }
44 if (!eq4(&a[8], &b[8])) {
45 return false;
46 }
47 return eq4(&a[12], &b[12]);
48#endif
49}
50
51///////////////////////////////////////////////////////////////////////////////
52
53int SkMatrix44::computeTypeMask() const {
54 unsigned mask = 0;
skia.committer@gmail.com0264fb42012-12-06 02:01:25 +000055
reed@google.com7d683352012-12-03 21:19:52 +000056 if (0 != perspX() || 0 != perspY() || 0 != perspZ() || 1 != fMat[3][3]) {
57 return kTranslate_Mask | kScale_Mask | kAffine_Mask | kPerspective_Mask;
58 }
59
60 if (0 != transX() || 0 != transY() || 0 != transZ()) {
61 mask |= kTranslate_Mask;
62 }
63
64 if (1 != scaleX() || 1 != scaleY() || 1 != scaleZ()) {
65 mask |= kScale_Mask;
66 }
67
68 if (0 != fMat[1][0] || 0 != fMat[0][1] || 0 != fMat[0][2] ||
69 0 != fMat[2][0] || 0 != fMat[1][2] || 0 != fMat[2][1]) {
70 mask |= kAffine_Mask;
71 }
72
73 return mask;
reed@google.com8260a892011-06-13 14:02:52 +000074}
75
76///////////////////////////////////////////////////////////////////////////////
77
reed@google.comda9fac02011-06-13 14:46:52 +000078void SkMatrix44::asColMajorf(float dst[]) const {
79 const SkMScalar* src = &fMat[0][0];
80#ifdef SK_MSCALAR_IS_DOUBLE
81 for (int i = 0; i < 16; ++i) {
82 dst[i] = SkMScalarToFloat(src[i]);
83 }
vollick@chromium.org5596a692012-11-13 20:12:00 +000084#elif defined SK_MSCALAR_IS_FLOAT
reed@google.comda9fac02011-06-13 14:46:52 +000085 memcpy(dst, src, 16 * sizeof(float));
86#endif
87}
88
brianosmande68d6c2016-09-09 10:36:17 -070089void SkMatrix44::as3x4RowMajorf(float dst[]) const {
90 dst[0] = fMat[0][0]; dst[1] = fMat[1][0]; dst[2] = fMat[2][0]; dst[3] = fMat[3][0];
91 dst[4] = fMat[0][1]; dst[5] = fMat[1][1]; dst[6] = fMat[2][1]; dst[7] = fMat[3][1];
92 dst[8] = fMat[0][2]; dst[9] = fMat[1][2]; dst[10] = fMat[2][2]; dst[11] = fMat[3][2];
msarett111a42d2016-06-22 08:18:54 -070093}
94
reed@google.comda9fac02011-06-13 14:46:52 +000095void SkMatrix44::asColMajord(double dst[]) const {
96 const SkMScalar* src = &fMat[0][0];
97#ifdef SK_MSCALAR_IS_DOUBLE
98 memcpy(dst, src, 16 * sizeof(double));
vollick@chromium.org5596a692012-11-13 20:12:00 +000099#elif defined SK_MSCALAR_IS_FLOAT
reed@google.comda9fac02011-06-13 14:46:52 +0000100 for (int i = 0; i < 16; ++i) {
101 dst[i] = SkMScalarToDouble(src[i]);
102 }
103#endif
104}
105
106void SkMatrix44::asRowMajorf(float dst[]) const {
107 const SkMScalar* src = &fMat[0][0];
108 for (int i = 0; i < 4; ++i) {
109 dst[0] = SkMScalarToFloat(src[0]);
110 dst[4] = SkMScalarToFloat(src[1]);
111 dst[8] = SkMScalarToFloat(src[2]);
112 dst[12] = SkMScalarToFloat(src[3]);
113 src += 4;
114 dst += 1;
115 }
116}
117
118void SkMatrix44::asRowMajord(double dst[]) const {
119 const SkMScalar* src = &fMat[0][0];
120 for (int i = 0; i < 4; ++i) {
121 dst[0] = SkMScalarToDouble(src[0]);
122 dst[4] = SkMScalarToDouble(src[1]);
123 dst[8] = SkMScalarToDouble(src[2]);
124 dst[12] = SkMScalarToDouble(src[3]);
125 src += 4;
126 dst += 1;
127 }
128}
129
vollick@chromium.orgf11cf9f2012-11-19 21:02:06 +0000130void SkMatrix44::setColMajorf(const float src[]) {
131 SkMScalar* dst = &fMat[0][0];
132#ifdef SK_MSCALAR_IS_DOUBLE
133 for (int i = 0; i < 16; ++i) {
134 dst[i] = SkMScalarToFloat(src[i]);
135 }
136#elif defined SK_MSCALAR_IS_FLOAT
137 memcpy(dst, src, 16 * sizeof(float));
138#endif
reed@google.com7d683352012-12-03 21:19:52 +0000139
140 this->dirtyTypeMask();
vollick@chromium.orgf11cf9f2012-11-19 21:02:06 +0000141}
142
143void SkMatrix44::setColMajord(const double src[]) {
144 SkMScalar* dst = &fMat[0][0];
145#ifdef SK_MSCALAR_IS_DOUBLE
146 memcpy(dst, src, 16 * sizeof(double));
147#elif defined SK_MSCALAR_IS_FLOAT
148 for (int i = 0; i < 16; ++i) {
robertphillips@google.com93f03322012-12-03 17:35:19 +0000149 dst[i] = SkDoubleToMScalar(src[i]);
vollick@chromium.orgf11cf9f2012-11-19 21:02:06 +0000150 }
151#endif
reed@google.com7d683352012-12-03 21:19:52 +0000152
153 this->dirtyTypeMask();
vollick@chromium.orgf11cf9f2012-11-19 21:02:06 +0000154}
155
156void SkMatrix44::setRowMajorf(const float src[]) {
157 SkMScalar* dst = &fMat[0][0];
158 for (int i = 0; i < 4; ++i) {
159 dst[0] = SkMScalarToFloat(src[0]);
160 dst[4] = SkMScalarToFloat(src[1]);
161 dst[8] = SkMScalarToFloat(src[2]);
162 dst[12] = SkMScalarToFloat(src[3]);
163 src += 4;
164 dst += 1;
165 }
reed@google.com7d683352012-12-03 21:19:52 +0000166 this->dirtyTypeMask();
vollick@chromium.orgf11cf9f2012-11-19 21:02:06 +0000167}
168
169void SkMatrix44::setRowMajord(const double src[]) {
170 SkMScalar* dst = &fMat[0][0];
171 for (int i = 0; i < 4; ++i) {
robertphillips@google.com93f03322012-12-03 17:35:19 +0000172 dst[0] = SkDoubleToMScalar(src[0]);
173 dst[4] = SkDoubleToMScalar(src[1]);
174 dst[8] = SkDoubleToMScalar(src[2]);
175 dst[12] = SkDoubleToMScalar(src[3]);
vollick@chromium.orgf11cf9f2012-11-19 21:02:06 +0000176 src += 4;
177 dst += 1;
178 }
reed@google.com7d683352012-12-03 21:19:52 +0000179 this->dirtyTypeMask();
vollick@chromium.orgf11cf9f2012-11-19 21:02:06 +0000180}
181
reed@google.comda9fac02011-06-13 14:46:52 +0000182///////////////////////////////////////////////////////////////////////////////
183
reed@google.com7d683352012-12-03 21:19:52 +0000184const SkMatrix44& SkMatrix44::I() {
msarettc1a3e242016-06-23 12:42:29 -0700185 static constexpr SkMatrix44 gIdentity44(kIdentity_Constructor);
reed@google.com1adad342012-12-10 21:21:27 +0000186 return gIdentity44;
reed@google.com8260a892011-06-13 14:02:52 +0000187}
188
reed@google.com8260a892011-06-13 14:02:52 +0000189void SkMatrix44::setIdentity() {
shawnsingh@chromium.org5a6cd352013-08-28 18:55:25 +0000190 fMat[0][0] = 1;
191 fMat[0][1] = 0;
192 fMat[0][2] = 0;
193 fMat[0][3] = 0;
194 fMat[1][0] = 0;
195 fMat[1][1] = 1;
196 fMat[1][2] = 0;
197 fMat[1][3] = 0;
198 fMat[2][0] = 0;
199 fMat[2][1] = 0;
200 fMat[2][2] = 1;
201 fMat[2][3] = 0;
202 fMat[3][0] = 0;
203 fMat[3][1] = 0;
204 fMat[3][2] = 0;
205 fMat[3][3] = 1;
reed@google.com7d683352012-12-03 21:19:52 +0000206 this->setTypeMask(kIdentity_Mask);
reed@google.com8260a892011-06-13 14:02:52 +0000207}
208
Brian Osman2fda63a2018-04-20 12:04:06 -0400209void SkMatrix44::set3x3(SkMScalar m_00, SkMScalar m_10, SkMScalar m_20,
210 SkMScalar m_01, SkMScalar m_11, SkMScalar m_21,
211 SkMScalar m_02, SkMScalar m_12, SkMScalar m_22) {
212 fMat[0][0] = m_00; fMat[0][1] = m_10; fMat[0][2] = m_20; fMat[0][3] = 0;
213 fMat[1][0] = m_01; fMat[1][1] = m_11; fMat[1][2] = m_21; fMat[1][3] = 0;
214 fMat[2][0] = m_02; fMat[2][1] = m_12; fMat[2][2] = m_22; fMat[2][3] = 0;
215 fMat[3][0] = 0; fMat[3][1] = 0; fMat[3][2] = 0; fMat[3][3] = 1;
reed@google.com7d683352012-12-03 21:19:52 +0000216 this->dirtyTypeMask();
reed@google.com8260a892011-06-13 14:02:52 +0000217}
218
msarettc1a3e242016-06-23 12:42:29 -0700219void SkMatrix44::set3x3RowMajorf(const float src[]) {
reed50d3b572016-05-03 12:13:21 -0700220 fMat[0][0] = src[0]; fMat[0][1] = src[3]; fMat[0][2] = src[6]; fMat[0][3] = 0;
221 fMat[1][0] = src[1]; fMat[1][1] = src[4]; fMat[1][2] = src[7]; fMat[1][3] = 0;
222 fMat[2][0] = src[2]; fMat[2][1] = src[5]; fMat[2][2] = src[8]; fMat[2][3] = 0;
223 fMat[3][0] = 0; fMat[3][1] = 0; fMat[3][2] = 0; fMat[3][3] = 1;
224 this->dirtyTypeMask();
225}
226
brianosmande68d6c2016-09-09 10:36:17 -0700227void SkMatrix44::set3x4RowMajorf(const float src[]) {
228 fMat[0][0] = src[0]; fMat[1][0] = src[1]; fMat[2][0] = src[2]; fMat[3][0] = src[3];
229 fMat[0][1] = src[4]; fMat[1][1] = src[5]; fMat[2][1] = src[6]; fMat[3][1] = src[7];
230 fMat[0][2] = src[8]; fMat[1][2] = src[9]; fMat[2][2] = src[10]; fMat[3][2] = src[11];
231 fMat[0][3] = 0; fMat[1][3] = 0; fMat[2][3] = 0; fMat[3][3] = 1;
msarett111a42d2016-06-22 08:18:54 -0700232 this->dirtyTypeMask();
233}
234
reed@google.com8260a892011-06-13 14:02:52 +0000235///////////////////////////////////////////////////////////////////////////////
236
reed@google.com99b5c7f2012-12-05 22:13:59 +0000237void SkMatrix44::setTranslate(SkMScalar dx, SkMScalar dy, SkMScalar dz) {
reed@google.com8260a892011-06-13 14:02:52 +0000238 this->setIdentity();
skia.committer@gmail.come659c2e2012-12-04 02:01:25 +0000239
reed@google.com99b5c7f2012-12-05 22:13:59 +0000240 if (!dx && !dy && !dz) {
241 return;
reed@google.com7d683352012-12-03 21:19:52 +0000242 }
skia.committer@gmail.com0264fb42012-12-06 02:01:25 +0000243
reed@google.com99b5c7f2012-12-05 22:13:59 +0000244 fMat[3][0] = dx;
245 fMat[3][1] = dy;
246 fMat[3][2] = dz;
247 this->setTypeMask(kTranslate_Mask);
reed@google.com8260a892011-06-13 14:02:52 +0000248}
249
250void SkMatrix44::preTranslate(SkMScalar dx, SkMScalar dy, SkMScalar dz) {
reed@google.com99b5c7f2012-12-05 22:13:59 +0000251 if (!dx && !dy && !dz) {
252 return;
253 }
254
reed@google.com99b5c7f2012-12-05 22:13:59 +0000255 for (int i = 0; i < 4; ++i) {
commit-bot@chromium.org658e28b2013-10-29 21:08:51 +0000256 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 +0000257 }
258 this->dirtyTypeMask();
reed@google.com8260a892011-06-13 14:02:52 +0000259}
260
261void SkMatrix44::postTranslate(SkMScalar dx, SkMScalar dy, SkMScalar dz) {
reed@google.com99b5c7f2012-12-05 22:13:59 +0000262 if (!dx && !dy && !dz) {
263 return;
264 }
265
266 if (this->getType() & kPerspective_Mask) {
267 for (int i = 0; i < 4; ++i) {
268 fMat[i][0] += fMat[i][3] * dx;
269 fMat[i][1] += fMat[i][3] * dy;
270 fMat[i][2] += fMat[i][3] * dz;
271 }
272 } else {
273 fMat[3][0] += dx;
274 fMat[3][1] += dy;
275 fMat[3][2] += dz;
276 this->dirtyTypeMask();
277 }
reed@google.com8260a892011-06-13 14:02:52 +0000278}
279
280///////////////////////////////////////////////////////////////////////////////
281
282void SkMatrix44::setScale(SkMScalar sx, SkMScalar sy, SkMScalar sz) {
reed@google.com99b5c7f2012-12-05 22:13:59 +0000283 this->setIdentity();
284
285 if (1 == sx && 1 == sy && 1 == sz) {
286 return;
287 }
288
reed@google.com8260a892011-06-13 14:02:52 +0000289 fMat[0][0] = sx;
290 fMat[1][1] = sy;
291 fMat[2][2] = sz;
reed@google.com99b5c7f2012-12-05 22:13:59 +0000292 this->setTypeMask(kScale_Mask);
reed@google.com8260a892011-06-13 14:02:52 +0000293}
294
295void SkMatrix44::preScale(SkMScalar sx, SkMScalar sy, SkMScalar sz) {
reed@google.com99b5c7f2012-12-05 22:13:59 +0000296 if (1 == sx && 1 == sy && 1 == sz) {
297 return;
298 }
skia.committer@gmail.com0264fb42012-12-06 02:01:25 +0000299
shawnsingh@chromium.orgf81f97e2012-12-13 22:21:36 +0000300 // The implementation matrix * pureScale can be shortcut
301 // by knowing that pureScale components effectively scale
302 // the columns of the original matrix.
303 for (int i = 0; i < 4; i++) {
304 fMat[0][i] *= sx;
305 fMat[1][i] *= sy;
306 fMat[2][i] *= sz;
307 }
308 this->dirtyTypeMask();
reed@google.com8260a892011-06-13 14:02:52 +0000309}
310
311void SkMatrix44::postScale(SkMScalar sx, SkMScalar sy, SkMScalar sz) {
reed@google.com99b5c7f2012-12-05 22:13:59 +0000312 if (1 == sx && 1 == sy && 1 == sz) {
313 return;
314 }
skia.committer@gmail.com0264fb42012-12-06 02:01:25 +0000315
reed@google.com8260a892011-06-13 14:02:52 +0000316 for (int i = 0; i < 4; i++) {
317 fMat[i][0] *= sx;
318 fMat[i][1] *= sy;
319 fMat[i][2] *= sz;
320 }
reed@google.com7d683352012-12-03 21:19:52 +0000321 this->dirtyTypeMask();
reed@google.com8260a892011-06-13 14:02:52 +0000322}
323
324///////////////////////////////////////////////////////////////////////////////
325
326void SkMatrix44::setRotateAbout(SkMScalar x, SkMScalar y, SkMScalar z,
327 SkMScalar radians) {
reed@google.com7d683352012-12-03 21:19:52 +0000328 double len2 = (double)x * x + (double)y * y + (double)z * z;
329 if (1 != len2) {
330 if (0 == len2) {
reed@google.com8260a892011-06-13 14:02:52 +0000331 this->setIdentity();
332 return;
333 }
334 double scale = 1 / sqrt(len2);
bsalomon@google.com9d12f5c2011-09-29 18:08:18 +0000335 x = SkDoubleToMScalar(x * scale);
336 y = SkDoubleToMScalar(y * scale);
337 z = SkDoubleToMScalar(z * scale);
reed@google.com8260a892011-06-13 14:02:52 +0000338 }
339 this->setRotateAboutUnit(x, y, z, radians);
340}
341
342void SkMatrix44::setRotateAboutUnit(SkMScalar x, SkMScalar y, SkMScalar z,
343 SkMScalar radians) {
344 double c = cos(radians);
345 double s = sin(radians);
346 double C = 1 - c;
347 double xs = x * s;
348 double ys = y * s;
349 double zs = z * s;
350 double xC = x * C;
351 double yC = y * C;
352 double zC = z * C;
353 double xyC = x * yC;
354 double yzC = y * zC;
355 double zxC = z * xC;
356
357 // if you're looking at wikipedia, remember that we're column major.
bsalomon@google.com9d12f5c2011-09-29 18:08:18 +0000358 this->set3x3(SkDoubleToMScalar(x * xC + c), // scale x
359 SkDoubleToMScalar(xyC + zs), // skew x
360 SkDoubleToMScalar(zxC - ys), // trans x
361
362 SkDoubleToMScalar(xyC - zs), // skew y
363 SkDoubleToMScalar(y * yC + c), // scale y
364 SkDoubleToMScalar(yzC + xs), // trans y
365
366 SkDoubleToMScalar(zxC + ys), // persp x
367 SkDoubleToMScalar(yzC - xs), // persp y
368 SkDoubleToMScalar(z * zC + c)); // persp 2
reed@google.com8260a892011-06-13 14:02:52 +0000369}
370
371///////////////////////////////////////////////////////////////////////////////
372
reed@google.com99b5c7f2012-12-05 22:13:59 +0000373static bool bits_isonly(int value, int mask) {
374 return 0 == (value & ~mask);
375}
376
reed@google.com8260a892011-06-13 14:02:52 +0000377void SkMatrix44::setConcat(const SkMatrix44& a, const SkMatrix44& b) {
reed@google.com99b5c7f2012-12-05 22:13:59 +0000378 const SkMatrix44::TypeMask a_mask = a.getType();
379 const SkMatrix44::TypeMask b_mask = b.getType();
380
381 if (kIdentity_Mask == a_mask) {
reed@google.com7d683352012-12-03 21:19:52 +0000382 *this = b;
383 return;
384 }
reed@google.com99b5c7f2012-12-05 22:13:59 +0000385 if (kIdentity_Mask == b_mask) {
reed@google.com7d683352012-12-03 21:19:52 +0000386 *this = a;
387 return;
388 }
389
390 bool useStorage = (this == &a || this == &b);
391 SkMScalar storage[16];
392 SkMScalar* result = useStorage ? storage : &fMat[0][0];
393
reed@google.com2b165702013-01-17 16:01:19 +0000394 // Both matrices are at most scale+translate
reed@google.com99b5c7f2012-12-05 22:13:59 +0000395 if (bits_isonly(a_mask | b_mask, kScale_Mask | kTranslate_Mask)) {
reed@google.com99b5c7f2012-12-05 22:13:59 +0000396 result[0] = a.fMat[0][0] * b.fMat[0][0];
reed@google.com2b165702013-01-17 16:01:19 +0000397 result[1] = result[2] = result[3] = result[4] = 0;
reed@google.com99b5c7f2012-12-05 22:13:59 +0000398 result[5] = a.fMat[1][1] * b.fMat[1][1];
reed@google.com2b165702013-01-17 16:01:19 +0000399 result[6] = result[7] = result[8] = result[9] = 0;
reed@google.com99b5c7f2012-12-05 22:13:59 +0000400 result[10] = a.fMat[2][2] * b.fMat[2][2];
reed@google.com2b165702013-01-17 16:01:19 +0000401 result[11] = 0;
reed@google.com99b5c7f2012-12-05 22:13:59 +0000402 result[12] = a.fMat[0][0] * b.fMat[3][0] + a.fMat[3][0];
403 result[13] = a.fMat[1][1] * b.fMat[3][1] + a.fMat[3][1];
404 result[14] = a.fMat[2][2] * b.fMat[3][2] + a.fMat[3][2];
405 result[15] = 1;
406 } else {
407 for (int j = 0; j < 4; j++) {
408 for (int i = 0; i < 4; i++) {
commit-bot@chromium.orgbde4ba22014-01-24 18:48:00 +0000409 double value = 0;
reed@google.com99b5c7f2012-12-05 22:13:59 +0000410 for (int k = 0; k < 4; k++) {
commit-bot@chromium.orgbde4ba22014-01-24 18:48:00 +0000411 value += SkMScalarToDouble(a.fMat[k][i]) * b.fMat[j][k];
reed@google.com99b5c7f2012-12-05 22:13:59 +0000412 }
commit-bot@chromium.orgbde4ba22014-01-24 18:48:00 +0000413 *result++ = SkDoubleToMScalar(value);
reed@google.com8260a892011-06-13 14:02:52 +0000414 }
reed@google.com8260a892011-06-13 14:02:52 +0000415 }
416 }
reed@google.com99b5c7f2012-12-05 22:13:59 +0000417
reed@google.com7d683352012-12-03 21:19:52 +0000418 if (useStorage) {
tomhudson@google.com7cfb9c72013-01-17 13:29:35 +0000419 memcpy(fMat, storage, sizeof(storage));
reed@google.com7d683352012-12-03 21:19:52 +0000420 }
reed@google.com7d683352012-12-03 21:19:52 +0000421 this->dirtyTypeMask();
reed@google.com8260a892011-06-13 14:02:52 +0000422}
423
424///////////////////////////////////////////////////////////////////////////////
425
reed@google.com8260a892011-06-13 14:02:52 +0000426/** We always perform the calculation in doubles, to avoid prematurely losing
427 precision along the way. This relies on the compiler automatically
428 promoting our SkMScalar values to double (if needed).
429 */
430double SkMatrix44::determinant() const {
mike@reedtribe.orgf8b1ebc2012-12-10 03:27:47 +0000431 if (this->isIdentity()) {
432 return 1;
433 }
434 if (this->isScaleTranslate()) {
435 return fMat[0][0] * fMat[1][1] * fMat[2][2] * fMat[3][3];
436 }
437
tomhudson@google.com9973a8a2012-12-13 09:55:42 +0000438 double a00 = fMat[0][0];
439 double a01 = fMat[0][1];
440 double a02 = fMat[0][2];
441 double a03 = fMat[0][3];
442 double a10 = fMat[1][0];
443 double a11 = fMat[1][1];
444 double a12 = fMat[1][2];
445 double a13 = fMat[1][3];
446 double a20 = fMat[2][0];
447 double a21 = fMat[2][1];
448 double a22 = fMat[2][2];
449 double a23 = fMat[2][3];
450 double a30 = fMat[3][0];
451 double a31 = fMat[3][1];
452 double a32 = fMat[3][2];
453 double a33 = fMat[3][3];
454
455 double b00 = a00 * a11 - a01 * a10;
456 double b01 = a00 * a12 - a02 * a10;
457 double b02 = a00 * a13 - a03 * a10;
458 double b03 = a01 * a12 - a02 * a11;
459 double b04 = a01 * a13 - a03 * a11;
460 double b05 = a02 * a13 - a03 * a12;
461 double b06 = a20 * a31 - a21 * a30;
462 double b07 = a20 * a32 - a22 * a30;
463 double b08 = a20 * a33 - a23 * a30;
464 double b09 = a21 * a32 - a22 * a31;
465 double b10 = a21 * a33 - a23 * a31;
466 double b11 = a22 * a33 - a23 * a32;
467
468 // Calculate the determinant
469 return b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
reed@google.com8260a892011-06-13 14:02:52 +0000470}
471
472///////////////////////////////////////////////////////////////////////////////
473
vmpstra8d45592015-06-30 13:36:04 -0700474static bool is_matrix_finite(const SkMatrix44& matrix) {
475 SkMScalar accumulator = 0;
476 for (int row = 0; row < 4; ++row) {
477 for (int col = 0; col < 4; ++col) {
478 accumulator *= matrix.get(row, col);
479 }
480 }
481 return accumulator == 0;
482}
483
484bool SkMatrix44::invert(SkMatrix44* storage) const {
mike@reedtribe.orgf8b1ebc2012-12-10 03:27:47 +0000485 if (this->isIdentity()) {
vmpstra8d45592015-06-30 13:36:04 -0700486 if (storage) {
487 storage->setIdentity();
reed@google.com7d683352012-12-03 21:19:52 +0000488 }
commit-bot@chromium.org178acd22013-11-20 21:32:27 +0000489 return true;
reed@google.com7d683352012-12-03 21:19:52 +0000490 }
commit-bot@chromium.org178acd22013-11-20 21:32:27 +0000491
mike@reedtribe.orgf8b1ebc2012-12-10 03:27:47 +0000492 if (this->isTranslate()) {
vmpstra8d45592015-06-30 13:36:04 -0700493 if (storage) {
494 storage->setTranslate(-fMat[3][0], -fMat[3][1], -fMat[3][2]);
reed@google.com99b5c7f2012-12-05 22:13:59 +0000495 }
496 return true;
497 }
commit-bot@chromium.org178acd22013-11-20 21:32:27 +0000498
Mike Klein4429a4f2018-10-04 09:06:00 -0400499 SkMatrix44 tmp;
vmpstra8d45592015-06-30 13:36:04 -0700500 // Use storage if it's available and distinct from this matrix.
501 SkMatrix44* inverse = (storage && storage != this) ? storage : &tmp;
mike@reedtribe.orgf8b1ebc2012-12-10 03:27:47 +0000502 if (this->isScaleTranslate()) {
reed@google.com99b5c7f2012-12-05 22:13:59 +0000503 if (0 == fMat[0][0] * fMat[1][1] * fMat[2][2]) {
504 return false;
505 }
reed@google.com99b5c7f2012-12-05 22:13:59 +0000506
vmpstra8d45592015-06-30 13:36:04 -0700507 double invXScale = 1 / fMat[0][0];
508 double invYScale = 1 / fMat[1][1];
509 double invZScale = 1 / fMat[2][2];
reed@google.com99b5c7f2012-12-05 22:13:59 +0000510
vmpstra8d45592015-06-30 13:36:04 -0700511 inverse->fMat[0][0] = SkDoubleToMScalar(invXScale);
512 inverse->fMat[0][1] = 0;
513 inverse->fMat[0][2] = 0;
514 inverse->fMat[0][3] = 0;
skia.committer@gmail.com772c4e62013-08-30 07:01:34 +0000515
vmpstra8d45592015-06-30 13:36:04 -0700516 inverse->fMat[1][0] = 0;
517 inverse->fMat[1][1] = SkDoubleToMScalar(invYScale);
518 inverse->fMat[1][2] = 0;
519 inverse->fMat[1][3] = 0;
skia.committer@gmail.com772c4e62013-08-30 07:01:34 +0000520
vmpstra8d45592015-06-30 13:36:04 -0700521 inverse->fMat[2][0] = 0;
522 inverse->fMat[2][1] = 0;
523 inverse->fMat[2][2] = SkDoubleToMScalar(invZScale);
524 inverse->fMat[2][3] = 0;
skia.committer@gmail.com772c4e62013-08-30 07:01:34 +0000525
vmpstra8d45592015-06-30 13:36:04 -0700526 inverse->fMat[3][0] = SkDoubleToMScalar(-fMat[3][0] * invXScale);
527 inverse->fMat[3][1] = SkDoubleToMScalar(-fMat[3][1] * invYScale);
528 inverse->fMat[3][2] = SkDoubleToMScalar(-fMat[3][2] * invZScale);
529 inverse->fMat[3][3] = 1;
shawnsingh@chromium.orgb6823c12013-08-22 20:24:21 +0000530
vmpstra8d45592015-06-30 13:36:04 -0700531 inverse->setTypeMask(this->getType());
532
533 if (!is_matrix_finite(*inverse)) {
534 return false;
shawnsingh@chromium.org5a6cd352013-08-28 18:55:25 +0000535 }
vmpstra8d45592015-06-30 13:36:04 -0700536 if (storage && inverse != storage) {
537 *storage = *inverse;
538 }
reed@google.com99b5c7f2012-12-05 22:13:59 +0000539 return true;
540 }
541
tomhudson@google.com9973a8a2012-12-13 09:55:42 +0000542 double a00 = fMat[0][0];
543 double a01 = fMat[0][1];
544 double a02 = fMat[0][2];
545 double a03 = fMat[0][3];
546 double a10 = fMat[1][0];
547 double a11 = fMat[1][1];
548 double a12 = fMat[1][2];
549 double a13 = fMat[1][3];
550 double a20 = fMat[2][0];
551 double a21 = fMat[2][1];
552 double a22 = fMat[2][2];
553 double a23 = fMat[2][3];
554 double a30 = fMat[3][0];
555 double a31 = fMat[3][1];
556 double a32 = fMat[3][2];
557 double a33 = fMat[3][3];
558
shawnsingh@chromium.orgb6823c12013-08-22 20:24:21 +0000559 if (!(this->getType() & kPerspective_Mask)) {
560 // If we know the matrix has no perspective, then the perspective
561 // component is (0, 0, 0, 1). We can use this information to save a lot
562 // of arithmetic that would otherwise be spent to compute the inverse
563 // of a general matrix.
564
565 SkASSERT(a03 == 0);
566 SkASSERT(a13 == 0);
567 SkASSERT(a23 == 0);
568 SkASSERT(a33 == 1);
569
570 double b00 = a00 * a11 - a01 * a10;
571 double b01 = a00 * a12 - a02 * a10;
572 double b03 = a01 * a12 - a02 * a11;
573 double b06 = a20 * a31 - a21 * a30;
574 double b07 = a20 * a32 - a22 * a30;
575 double b08 = a20;
576 double b09 = a21 * a32 - a22 * a31;
577 double b10 = a21;
578 double b11 = a22;
579
580 // Calculate the determinant
581 double det = b00 * b11 - b01 * b10 + b03 * b08;
582
Mike Reed9236b022018-05-14 13:37:16 -0400583 double invdet = sk_ieee_double_divide(1.0, det);
shawnsingh@chromium.orgb6823c12013-08-22 20:24:21 +0000584 // If det is zero, we want to return false. However, we also want to return false
585 // if 1/det overflows to infinity (i.e. det is denormalized). Both of these are
586 // handled by checking that 1/det is finite.
Mike Reed9236b022018-05-14 13:37:16 -0400587 if (!sk_float_isfinite(sk_double_to_float(invdet))) {
shawnsingh@chromium.orgb6823c12013-08-22 20:24:21 +0000588 return false;
589 }
shawnsingh@chromium.orgb6823c12013-08-22 20:24:21 +0000590
591 b00 *= invdet;
592 b01 *= invdet;
593 b03 *= invdet;
594 b06 *= invdet;
595 b07 *= invdet;
596 b08 *= invdet;
597 b09 *= invdet;
598 b10 *= invdet;
599 b11 *= invdet;
600
601 inverse->fMat[0][0] = SkDoubleToMScalar(a11 * b11 - a12 * b10);
602 inverse->fMat[0][1] = SkDoubleToMScalar(a02 * b10 - a01 * b11);
603 inverse->fMat[0][2] = SkDoubleToMScalar(b03);
604 inverse->fMat[0][3] = 0;
605 inverse->fMat[1][0] = SkDoubleToMScalar(a12 * b08 - a10 * b11);
606 inverse->fMat[1][1] = SkDoubleToMScalar(a00 * b11 - a02 * b08);
607 inverse->fMat[1][2] = SkDoubleToMScalar(-b01);
608 inverse->fMat[1][3] = 0;
609 inverse->fMat[2][0] = SkDoubleToMScalar(a10 * b10 - a11 * b08);
610 inverse->fMat[2][1] = SkDoubleToMScalar(a01 * b08 - a00 * b10);
611 inverse->fMat[2][2] = SkDoubleToMScalar(b00);
612 inverse->fMat[2][3] = 0;
613 inverse->fMat[3][0] = SkDoubleToMScalar(a11 * b07 - a10 * b09 - a12 * b06);
614 inverse->fMat[3][1] = SkDoubleToMScalar(a00 * b09 - a01 * b07 + a02 * b06);
615 inverse->fMat[3][2] = SkDoubleToMScalar(a31 * b01 - a30 * b03 - a32 * b00);
616 inverse->fMat[3][3] = 1;
617
618 inverse->setTypeMask(this->getType());
vmpstra8d45592015-06-30 13:36:04 -0700619 if (!is_matrix_finite(*inverse)) {
620 return false;
621 }
622 if (storage && inverse != storage) {
623 *storage = *inverse;
624 }
shawnsingh@chromium.orgb6823c12013-08-22 20:24:21 +0000625 return true;
626 }
627
tomhudson@google.com9973a8a2012-12-13 09:55:42 +0000628 double b00 = a00 * a11 - a01 * a10;
629 double b01 = a00 * a12 - a02 * a10;
630 double b02 = a00 * a13 - a03 * a10;
631 double b03 = a01 * a12 - a02 * a11;
632 double b04 = a01 * a13 - a03 * a11;
633 double b05 = a02 * a13 - a03 * a12;
634 double b06 = a20 * a31 - a21 * a30;
635 double b07 = a20 * a32 - a22 * a30;
636 double b08 = a20 * a33 - a23 * a30;
637 double b09 = a21 * a32 - a22 * a31;
638 double b10 = a21 * a33 - a23 * a31;
639 double b11 = a22 * a33 - a23 * a32;
640
641 // Calculate the determinant
642 double det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
643
Mike Reed9236b022018-05-14 13:37:16 -0400644 double invdet = sk_ieee_double_divide(1.0, det);
commit-bot@chromium.orgf02f0782013-08-20 15:25:04 +0000645 // If det is zero, we want to return false. However, we also want to return false
646 // if 1/det overflows to infinity (i.e. det is denormalized). Both of these are
647 // handled by checking that 1/det is finite.
Mike Reed9236b022018-05-14 13:37:16 -0400648 if (!sk_float_isfinite(sk_double_to_float(invdet))) {
reed@google.com8260a892011-06-13 14:02:52 +0000649 return false;
650 }
reed@google.com8260a892011-06-13 14:02:52 +0000651
tomhudson@google.com9973a8a2012-12-13 09:55:42 +0000652 b00 *= invdet;
653 b01 *= invdet;
654 b02 *= invdet;
655 b03 *= invdet;
656 b04 *= invdet;
657 b05 *= invdet;
658 b06 *= invdet;
659 b07 *= invdet;
660 b08 *= invdet;
661 b09 *= invdet;
662 b10 *= invdet;
663 b11 *= invdet;
reed@google.com8260a892011-06-13 14:02:52 +0000664
tomhudson@google.com9973a8a2012-12-13 09:55:42 +0000665 inverse->fMat[0][0] = SkDoubleToMScalar(a11 * b11 - a12 * b10 + a13 * b09);
666 inverse->fMat[0][1] = SkDoubleToMScalar(a02 * b10 - a01 * b11 - a03 * b09);
667 inverse->fMat[0][2] = SkDoubleToMScalar(a31 * b05 - a32 * b04 + a33 * b03);
668 inverse->fMat[0][3] = SkDoubleToMScalar(a22 * b04 - a21 * b05 - a23 * b03);
669 inverse->fMat[1][0] = SkDoubleToMScalar(a12 * b08 - a10 * b11 - a13 * b07);
670 inverse->fMat[1][1] = SkDoubleToMScalar(a00 * b11 - a02 * b08 + a03 * b07);
671 inverse->fMat[1][2] = SkDoubleToMScalar(a32 * b02 - a30 * b05 - a33 * b01);
672 inverse->fMat[1][3] = SkDoubleToMScalar(a20 * b05 - a22 * b02 + a23 * b01);
673 inverse->fMat[2][0] = SkDoubleToMScalar(a10 * b10 - a11 * b08 + a13 * b06);
674 inverse->fMat[2][1] = SkDoubleToMScalar(a01 * b08 - a00 * b10 - a03 * b06);
675 inverse->fMat[2][2] = SkDoubleToMScalar(a30 * b04 - a31 * b02 + a33 * b00);
676 inverse->fMat[2][3] = SkDoubleToMScalar(a21 * b02 - a20 * b04 - a23 * b00);
677 inverse->fMat[3][0] = SkDoubleToMScalar(a11 * b07 - a10 * b09 - a12 * b06);
678 inverse->fMat[3][1] = SkDoubleToMScalar(a00 * b09 - a01 * b07 + a02 * b06);
679 inverse->fMat[3][2] = SkDoubleToMScalar(a31 * b01 - a30 * b03 - a32 * b00);
680 inverse->fMat[3][3] = SkDoubleToMScalar(a20 * b03 - a21 * b01 + a22 * b00);
681 inverse->dirtyTypeMask();
reed@google.com8260a892011-06-13 14:02:52 +0000682
vmpstra8d45592015-06-30 13:36:04 -0700683 inverse->setTypeMask(this->getType());
684 if (!is_matrix_finite(*inverse)) {
685 return false;
686 }
687 if (storage && inverse != storage) {
688 *storage = *inverse;
689 }
reed@google.com8260a892011-06-13 14:02:52 +0000690 return true;
691}
692
693///////////////////////////////////////////////////////////////////////////////
694
vollick@chromium.org9b21c252012-11-14 21:33:55 +0000695void SkMatrix44::transpose() {
Ben Wagnerf08d1d02018-06-18 15:11:00 -0400696 using std::swap;
697 swap(fMat[0][1], fMat[1][0]);
698 swap(fMat[0][2], fMat[2][0]);
699 swap(fMat[0][3], fMat[3][0]);
700 swap(fMat[1][2], fMat[2][1]);
701 swap(fMat[1][3], fMat[3][1]);
702 swap(fMat[2][3], fMat[3][2]);
reed@google.com7d683352012-12-03 21:19:52 +0000703
704 if (!this->isTriviallyIdentity()) {
705 this->dirtyTypeMask();
706 }
vollick@chromium.org9b21c252012-11-14 21:33:55 +0000707}
708
709///////////////////////////////////////////////////////////////////////////////
710
reed@google.com1ea95be2012-11-09 21:39:48 +0000711void SkMatrix44::mapScalars(const SkScalar src[4], SkScalar dst[4]) const {
reed@google.com7d683352012-12-03 21:19:52 +0000712 SkScalar storage[4];
713 SkScalar* result = (src == dst) ? storage : dst;
714
reed@google.com8260a892011-06-13 14:02:52 +0000715 for (int i = 0; i < 4; i++) {
716 SkMScalar value = 0;
717 for (int j = 0; j < 4; j++) {
718 value += fMat[j][i] * src[j];
719 }
bsalomon@google.com72e49b82011-10-27 21:47:03 +0000720 result[i] = SkMScalarToScalar(value);
reed@google.com8260a892011-06-13 14:02:52 +0000721 }
skia.committer@gmail.com0264fb42012-12-06 02:01:25 +0000722
reed@google.com7d683352012-12-03 21:19:52 +0000723 if (storage == result) {
724 memcpy(dst, storage, sizeof(storage));
725 }
reed@google.com8260a892011-06-13 14:02:52 +0000726}
727
reed@google.com1ea95be2012-11-09 21:39:48 +0000728#ifdef SK_MSCALAR_IS_DOUBLE
reed@google.com7d683352012-12-03 21:19:52 +0000729
reed@google.com1ea95be2012-11-09 21:39:48 +0000730void SkMatrix44::mapMScalars(const SkMScalar src[4], SkMScalar dst[4]) const {
reed@google.com7d683352012-12-03 21:19:52 +0000731 SkMScalar storage[4];
732 SkMScalar* result = (src == dst) ? storage : dst;
skia.committer@gmail.com0264fb42012-12-06 02:01:25 +0000733
reed@google.com1ea95be2012-11-09 21:39:48 +0000734 for (int i = 0; i < 4; i++) {
735 SkMScalar value = 0;
736 for (int j = 0; j < 4; j++) {
737 value += fMat[j][i] * src[j];
738 }
reed@google.com7d683352012-12-03 21:19:52 +0000739 result[i] = value;
reed@google.com1ea95be2012-11-09 21:39:48 +0000740 }
skia.committer@gmail.com0264fb42012-12-06 02:01:25 +0000741
reed@google.com7d683352012-12-03 21:19:52 +0000742 if (storage == result) {
743 memcpy(dst, storage, sizeof(storage));
744 }
reed@google.com1ea95be2012-11-09 21:39:48 +0000745}
reed@google.com7d683352012-12-03 21:19:52 +0000746
reed@google.com1ea95be2012-11-09 21:39:48 +0000747#endif
748
reed@google.com99b5c7f2012-12-05 22:13:59 +0000749typedef void (*Map2Procf)(const SkMScalar mat[][4], const float src2[], int count, float dst4[]);
750typedef void (*Map2Procd)(const SkMScalar mat[][4], const double src2[], int count, double dst4[]);
751
752static void map2_if(const SkMScalar mat[][4], const float* SK_RESTRICT src2,
753 int count, float* SK_RESTRICT dst4) {
754 for (int i = 0; i < count; ++i) {
755 dst4[0] = src2[0];
756 dst4[1] = src2[1];
757 dst4[2] = 0;
758 dst4[3] = 1;
759 src2 += 2;
760 dst4 += 4;
761 }
762}
763
764static void map2_id(const SkMScalar mat[][4], const double* SK_RESTRICT src2,
765 int count, double* SK_RESTRICT dst4) {
766 for (int i = 0; i < count; ++i) {
767 dst4[0] = src2[0];
768 dst4[1] = src2[1];
769 dst4[2] = 0;
770 dst4[3] = 1;
771 src2 += 2;
772 dst4 += 4;
773 }
774}
775
776static void map2_tf(const SkMScalar mat[][4], const float* SK_RESTRICT src2,
777 int count, float* SK_RESTRICT dst4) {
778 const float mat30 = SkMScalarToFloat(mat[3][0]);
779 const float mat31 = SkMScalarToFloat(mat[3][1]);
780 const float mat32 = SkMScalarToFloat(mat[3][2]);
781 for (int n = 0; n < count; ++n) {
782 dst4[0] = src2[0] + mat30;
783 dst4[1] = src2[1] + mat31;
784 dst4[2] = mat32;
785 dst4[3] = 1;
786 src2 += 2;
787 dst4 += 4;
788 }
789}
790
791static void map2_td(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 dst4[0] = src2[0] + mat[3][0];
795 dst4[1] = src2[1] + mat[3][1];
796 dst4[2] = mat[3][2];
797 dst4[3] = 1;
798 src2 += 2;
799 dst4 += 4;
800 }
801}
802
803static void map2_sf(const SkMScalar mat[][4], const float* SK_RESTRICT src2,
804 int count, float* SK_RESTRICT dst4) {
805 const float mat32 = SkMScalarToFloat(mat[3][2]);
806 for (int n = 0; n < count; ++n) {
807 dst4[0] = SkMScalarToFloat(mat[0][0] * src2[0] + mat[3][0]);
808 dst4[1] = SkMScalarToFloat(mat[1][1] * src2[1] + mat[3][1]);
809 dst4[2] = mat32;
810 dst4[3] = 1;
811 src2 += 2;
812 dst4 += 4;
813 }
814}
815
816static void map2_sd(const SkMScalar mat[][4], const double* SK_RESTRICT src2,
817 int count, double* SK_RESTRICT dst4) {
818 for (int n = 0; n < count; ++n) {
819 dst4[0] = mat[0][0] * src2[0] + mat[3][0];
820 dst4[1] = mat[1][1] * src2[1] + mat[3][1];
821 dst4[2] = mat[3][2];
822 dst4[3] = 1;
823 src2 += 2;
824 dst4 += 4;
825 }
826}
827
828static void map2_af(const SkMScalar mat[][4], const float* SK_RESTRICT src2,
829 int count, float* SK_RESTRICT dst4) {
commit-bot@chromium.org658e28b2013-10-29 21:08:51 +0000830 SkMScalar r;
reed@google.com99b5c7f2012-12-05 22:13:59 +0000831 for (int n = 0; n < count; ++n) {
commit-bot@chromium.org658e28b2013-10-29 21:08:51 +0000832 SkMScalar sx = SkFloatToMScalar(src2[0]);
833 SkMScalar sy = SkFloatToMScalar(src2[1]);
reed@google.com99b5c7f2012-12-05 22:13:59 +0000834 r = mat[0][0] * sx + mat[1][0] * sy + mat[3][0];
835 dst4[0] = SkMScalarToFloat(r);
836 r = mat[0][1] * sx + mat[1][1] * sy + mat[3][1];
837 dst4[1] = SkMScalarToFloat(r);
838 r = mat[0][2] * sx + mat[1][2] * sy + mat[3][2];
839 dst4[2] = SkMScalarToFloat(r);
840 dst4[3] = 1;
841 src2 += 2;
842 dst4 += 4;
843 }
844}
845
846static void map2_ad(const SkMScalar mat[][4], const double* SK_RESTRICT src2,
847 int count, double* SK_RESTRICT dst4) {
848 for (int n = 0; n < count; ++n) {
849 double sx = src2[0];
850 double sy = src2[1];
851 dst4[0] = mat[0][0] * sx + mat[1][0] * sy + mat[3][0];
852 dst4[1] = mat[0][1] * sx + mat[1][1] * sy + mat[3][1];
853 dst4[2] = mat[0][2] * sx + mat[1][2] * sy + mat[3][2];
854 dst4[3] = 1;
855 src2 += 2;
856 dst4 += 4;
857 }
858}
859
860static void map2_pf(const SkMScalar mat[][4], const float* SK_RESTRICT src2,
861 int count, float* SK_RESTRICT dst4) {
commit-bot@chromium.org658e28b2013-10-29 21:08:51 +0000862 SkMScalar r;
reed@google.com99b5c7f2012-12-05 22:13:59 +0000863 for (int n = 0; n < count; ++n) {
commit-bot@chromium.org658e28b2013-10-29 21:08:51 +0000864 SkMScalar sx = SkFloatToMScalar(src2[0]);
865 SkMScalar sy = SkFloatToMScalar(src2[1]);
reed@google.com99b5c7f2012-12-05 22:13:59 +0000866 for (int i = 0; i < 4; i++) {
commit-bot@chromium.org658e28b2013-10-29 21:08:51 +0000867 r = mat[0][i] * sx + mat[1][i] * sy + mat[3][i];
868 dst4[i] = SkMScalarToFloat(r);
reed@google.com99b5c7f2012-12-05 22:13:59 +0000869 }
870 src2 += 2;
871 dst4 += 4;
872 }
873}
874
875static void map2_pd(const SkMScalar mat[][4], const double* SK_RESTRICT src2,
876 int count, double* SK_RESTRICT dst4) {
877 for (int n = 0; n < count; ++n) {
878 double sx = src2[0];
879 double sy = src2[1];
880 for (int i = 0; i < 4; i++) {
881 dst4[i] = mat[0][i] * sx + mat[1][i] * sy + mat[3][i];
882 }
883 src2 += 2;
884 dst4 += 4;
885 }
886}
887
888void SkMatrix44::map2(const float src2[], int count, float dst4[]) const {
889 static const Map2Procf gProc[] = {
890 map2_if, map2_tf, map2_sf, map2_sf, map2_af, map2_af, map2_af, map2_af
891 };
892
893 TypeMask mask = this->getType();
894 Map2Procf proc = (mask & kPerspective_Mask) ? map2_pf : gProc[mask];
895 proc(fMat, src2, count, dst4);
896}
897
898void SkMatrix44::map2(const double src2[], int count, double dst4[]) const {
899 static const Map2Procd gProc[] = {
900 map2_id, map2_td, map2_sd, map2_sd, map2_ad, map2_ad, map2_ad, map2_ad
901 };
skia.committer@gmail.com0264fb42012-12-06 02:01:25 +0000902
reed@google.com99b5c7f2012-12-05 22:13:59 +0000903 TypeMask mask = this->getType();
904 Map2Procd proc = (mask & kPerspective_Mask) ? map2_pd : gProc[mask];
905 proc(fMat, src2, count, dst4);
906}
907
tomhudsonfaccb8e2014-09-26 11:45:48 -0700908bool SkMatrix44::preserves2dAxisAlignment (SkMScalar epsilon) const {
909
910 // Can't check (mask & kPerspective_Mask) because Z isn't relevant here.
911 if (0 != perspX() || 0 != perspY()) return false;
912
913 // A matrix with two non-zeroish values in any of the upper right
914 // rows or columns will skew. If only one value in each row or
915 // column is non-zeroish, we get a scale plus perhaps a 90-degree
916 // rotation.
917 int col0 = 0;
918 int col1 = 0;
919 int row0 = 0;
920 int row1 = 0;
921
922 // Must test against epsilon, not 0, because we can get values
923 // around 6e-17 in the matrix that "should" be 0.
924
925 if (SkMScalarAbs(fMat[0][0]) > epsilon) {
926 col0++;
927 row0++;
928 }
929 if (SkMScalarAbs(fMat[0][1]) > epsilon) {
930 col1++;
931 row0++;
932 }
933 if (SkMScalarAbs(fMat[1][0]) > epsilon) {
934 col0++;
935 row1++;
936 }
937 if (SkMScalarAbs(fMat[1][1]) > epsilon) {
938 col1++;
939 row1++;
940 }
941 if (col0 > 1 || col1 > 1 || row0 > 1 || row1 > 1) {
942 return false;
943 }
944
945 return true;
946}
947
reed@google.com8260a892011-06-13 14:02:52 +0000948///////////////////////////////////////////////////////////////////////////////
949
950void SkMatrix44::dump() const {
Mike Klein271daba2016-12-01 16:11:07 -0500951 static const char* format = "|%g %g %g %g|\n"
952 "|%g %g %g %g|\n"
953 "|%g %g %g %g|\n"
954 "|%g %g %g %g|\n";
tomhudson@google.com9ac4a892011-06-28 13:53:13 +0000955 SkDebugf(format,
reed@google.com8260a892011-06-13 14:02:52 +0000956 fMat[0][0], fMat[1][0], fMat[2][0], fMat[3][0],
957 fMat[0][1], fMat[1][1], fMat[2][1], fMat[3][1],
958 fMat[0][2], fMat[1][2], fMat[2][2], fMat[3][2],
959 fMat[0][3], fMat[1][3], fMat[2][3], fMat[3][3]);
reed@google.com8260a892011-06-13 14:02:52 +0000960}
961
962///////////////////////////////////////////////////////////////////////////////
963
964static void initFromMatrix(SkMScalar dst[4][4], const SkMatrix& src) {
bsalomon@google.com72e49b82011-10-27 21:47:03 +0000965 dst[0][0] = SkScalarToMScalar(src[SkMatrix::kMScaleX]);
966 dst[1][0] = SkScalarToMScalar(src[SkMatrix::kMSkewX]);
shawnsingh@chromium.org5a6cd352013-08-28 18:55:25 +0000967 dst[2][0] = 0;
bsalomon@google.com72e49b82011-10-27 21:47:03 +0000968 dst[3][0] = SkScalarToMScalar(src[SkMatrix::kMTransX]);
969 dst[0][1] = SkScalarToMScalar(src[SkMatrix::kMSkewY]);
970 dst[1][1] = SkScalarToMScalar(src[SkMatrix::kMScaleY]);
shawnsingh@chromium.org5a6cd352013-08-28 18:55:25 +0000971 dst[2][1] = 0;
bsalomon@google.com72e49b82011-10-27 21:47:03 +0000972 dst[3][1] = SkScalarToMScalar(src[SkMatrix::kMTransY]);
shawnsingh@chromium.org5a6cd352013-08-28 18:55:25 +0000973 dst[0][2] = 0;
974 dst[1][2] = 0;
975 dst[2][2] = 1;
976 dst[3][2] = 0;
commit-bot@chromium.org722555b2013-10-05 01:16:30 +0000977 dst[0][3] = SkScalarToMScalar(src[SkMatrix::kMPersp0]);
978 dst[1][3] = SkScalarToMScalar(src[SkMatrix::kMPersp1]);
shawnsingh@chromium.org5a6cd352013-08-28 18:55:25 +0000979 dst[2][3] = 0;
commit-bot@chromium.org722555b2013-10-05 01:16:30 +0000980 dst[3][3] = SkScalarToMScalar(src[SkMatrix::kMPersp2]);
reed@google.com8260a892011-06-13 14:02:52 +0000981}
982
983SkMatrix44::SkMatrix44(const SkMatrix& src) {
fs88640cf2014-12-16 08:36:11 -0800984 this->operator=(src);
reed@google.com8260a892011-06-13 14:02:52 +0000985}
986
987SkMatrix44& SkMatrix44::operator=(const SkMatrix& src) {
988 initFromMatrix(fMat, src);
reed@google.com7d683352012-12-03 21:19:52 +0000989
990 if (src.isIdentity()) {
991 this->setTypeMask(kIdentity_Mask);
992 } else {
993 this->dirtyTypeMask();
994 }
reed@google.com8260a892011-06-13 14:02:52 +0000995 return *this;
996}
997
998SkMatrix44::operator SkMatrix() const {
999 SkMatrix dst;
reed@google.com8260a892011-06-13 14:02:52 +00001000
bsalomon@google.com72e49b82011-10-27 21:47:03 +00001001 dst[SkMatrix::kMScaleX] = SkMScalarToScalar(fMat[0][0]);
1002 dst[SkMatrix::kMSkewX] = SkMScalarToScalar(fMat[1][0]);
1003 dst[SkMatrix::kMTransX] = SkMScalarToScalar(fMat[3][0]);
reed@google.com8260a892011-06-13 14:02:52 +00001004
bsalomon@google.com72e49b82011-10-27 21:47:03 +00001005 dst[SkMatrix::kMSkewY] = SkMScalarToScalar(fMat[0][1]);
1006 dst[SkMatrix::kMScaleY] = SkMScalarToScalar(fMat[1][1]);
1007 dst[SkMatrix::kMTransY] = SkMScalarToScalar(fMat[3][1]);
reed@google.com8260a892011-06-13 14:02:52 +00001008
commit-bot@chromium.org722555b2013-10-05 01:16:30 +00001009 dst[SkMatrix::kMPersp0] = SkMScalarToScalar(fMat[0][3]);
1010 dst[SkMatrix::kMPersp1] = SkMScalarToScalar(fMat[1][3]);
1011 dst[SkMatrix::kMPersp2] = SkMScalarToScalar(fMat[3][3]);
1012
reed@google.com8260a892011-06-13 14:02:52 +00001013 return dst;
1014}