blob: 818f23af5a4f06b6a098238d257245e3245c5061 [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
brianosmande68d6c2016-09-09 10:36:17 -070088void SkMatrix44::as3x4RowMajorf(float dst[]) const {
89 dst[0] = fMat[0][0]; dst[1] = fMat[1][0]; dst[2] = fMat[2][0]; dst[3] = fMat[3][0];
90 dst[4] = fMat[0][1]; dst[5] = fMat[1][1]; dst[6] = fMat[2][1]; dst[7] = fMat[3][1];
91 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 -070092}
93
reed@google.comda9fac02011-06-13 14:46:52 +000094void SkMatrix44::asColMajord(double dst[]) const {
95 const SkMScalar* src = &fMat[0][0];
96#ifdef SK_MSCALAR_IS_DOUBLE
97 memcpy(dst, src, 16 * sizeof(double));
vollick@chromium.org5596a692012-11-13 20:12:00 +000098#elif defined SK_MSCALAR_IS_FLOAT
reed@google.comda9fac02011-06-13 14:46:52 +000099 for (int i = 0; i < 16; ++i) {
100 dst[i] = SkMScalarToDouble(src[i]);
101 }
102#endif
103}
104
105void SkMatrix44::asRowMajorf(float dst[]) const {
106 const SkMScalar* src = &fMat[0][0];
107 for (int i = 0; i < 4; ++i) {
108 dst[0] = SkMScalarToFloat(src[0]);
109 dst[4] = SkMScalarToFloat(src[1]);
110 dst[8] = SkMScalarToFloat(src[2]);
111 dst[12] = SkMScalarToFloat(src[3]);
112 src += 4;
113 dst += 1;
114 }
115}
116
117void SkMatrix44::asRowMajord(double dst[]) const {
118 const SkMScalar* src = &fMat[0][0];
119 for (int i = 0; i < 4; ++i) {
120 dst[0] = SkMScalarToDouble(src[0]);
121 dst[4] = SkMScalarToDouble(src[1]);
122 dst[8] = SkMScalarToDouble(src[2]);
123 dst[12] = SkMScalarToDouble(src[3]);
124 src += 4;
125 dst += 1;
126 }
127}
128
vollick@chromium.orgf11cf9f2012-11-19 21:02:06 +0000129void SkMatrix44::setColMajorf(const float src[]) {
130 SkMScalar* dst = &fMat[0][0];
131#ifdef SK_MSCALAR_IS_DOUBLE
132 for (int i = 0; i < 16; ++i) {
133 dst[i] = SkMScalarToFloat(src[i]);
134 }
135#elif defined SK_MSCALAR_IS_FLOAT
136 memcpy(dst, src, 16 * sizeof(float));
137#endif
reed@google.com7d683352012-12-03 21:19:52 +0000138
139 this->dirtyTypeMask();
vollick@chromium.orgf11cf9f2012-11-19 21:02:06 +0000140}
141
142void SkMatrix44::setColMajord(const double src[]) {
143 SkMScalar* dst = &fMat[0][0];
144#ifdef SK_MSCALAR_IS_DOUBLE
145 memcpy(dst, src, 16 * sizeof(double));
146#elif defined SK_MSCALAR_IS_FLOAT
147 for (int i = 0; i < 16; ++i) {
robertphillips@google.com93f03322012-12-03 17:35:19 +0000148 dst[i] = SkDoubleToMScalar(src[i]);
vollick@chromium.orgf11cf9f2012-11-19 21:02:06 +0000149 }
150#endif
reed@google.com7d683352012-12-03 21:19:52 +0000151
152 this->dirtyTypeMask();
vollick@chromium.orgf11cf9f2012-11-19 21:02:06 +0000153}
154
155void SkMatrix44::setRowMajorf(const float src[]) {
156 SkMScalar* dst = &fMat[0][0];
157 for (int i = 0; i < 4; ++i) {
158 dst[0] = SkMScalarToFloat(src[0]);
159 dst[4] = SkMScalarToFloat(src[1]);
160 dst[8] = SkMScalarToFloat(src[2]);
161 dst[12] = SkMScalarToFloat(src[3]);
162 src += 4;
163 dst += 1;
164 }
reed@google.com7d683352012-12-03 21:19:52 +0000165 this->dirtyTypeMask();
vollick@chromium.orgf11cf9f2012-11-19 21:02:06 +0000166}
167
168void SkMatrix44::setRowMajord(const double src[]) {
169 SkMScalar* dst = &fMat[0][0];
170 for (int i = 0; i < 4; ++i) {
robertphillips@google.com93f03322012-12-03 17:35:19 +0000171 dst[0] = SkDoubleToMScalar(src[0]);
172 dst[4] = SkDoubleToMScalar(src[1]);
173 dst[8] = SkDoubleToMScalar(src[2]);
174 dst[12] = SkDoubleToMScalar(src[3]);
vollick@chromium.orgf11cf9f2012-11-19 21:02:06 +0000175 src += 4;
176 dst += 1;
177 }
reed@google.com7d683352012-12-03 21:19:52 +0000178 this->dirtyTypeMask();
vollick@chromium.orgf11cf9f2012-11-19 21:02:06 +0000179}
180
reed@google.comda9fac02011-06-13 14:46:52 +0000181///////////////////////////////////////////////////////////////////////////////
182
reed@google.com7d683352012-12-03 21:19:52 +0000183const SkMatrix44& SkMatrix44::I() {
msarettc1a3e242016-06-23 12:42:29 -0700184 static constexpr SkMatrix44 gIdentity44(kIdentity_Constructor);
reed@google.com1adad342012-12-10 21:21:27 +0000185 return gIdentity44;
reed@google.com8260a892011-06-13 14:02:52 +0000186}
187
reed@google.com8260a892011-06-13 14:02:52 +0000188void SkMatrix44::setIdentity() {
shawnsingh@chromium.org5a6cd352013-08-28 18:55:25 +0000189 fMat[0][0] = 1;
190 fMat[0][1] = 0;
191 fMat[0][2] = 0;
192 fMat[0][3] = 0;
193 fMat[1][0] = 0;
194 fMat[1][1] = 1;
195 fMat[1][2] = 0;
196 fMat[1][3] = 0;
197 fMat[2][0] = 0;
198 fMat[2][1] = 0;
199 fMat[2][2] = 1;
200 fMat[2][3] = 0;
201 fMat[3][0] = 0;
202 fMat[3][1] = 0;
203 fMat[3][2] = 0;
204 fMat[3][3] = 1;
reed@google.com7d683352012-12-03 21:19:52 +0000205 this->setTypeMask(kIdentity_Mask);
reed@google.com8260a892011-06-13 14:02:52 +0000206}
207
208void SkMatrix44::set3x3(SkMScalar m00, SkMScalar m01, SkMScalar m02,
209 SkMScalar m10, SkMScalar m11, SkMScalar m12,
210 SkMScalar m20, SkMScalar m21, SkMScalar m22) {
reed@google.com8260a892011-06-13 14:02:52 +0000211 fMat[0][0] = m00; fMat[0][1] = m01; fMat[0][2] = m02; fMat[0][3] = 0;
212 fMat[1][0] = m10; fMat[1][1] = m11; fMat[1][2] = m12; fMat[1][3] = 0;
213 fMat[2][0] = m20; fMat[2][1] = m21; fMat[2][2] = m22; fMat[2][3] = 0;
214 fMat[3][0] = 0; fMat[3][1] = 0; fMat[3][2] = 0; fMat[3][3] = 1;
reed@google.com7d683352012-12-03 21:19:52 +0000215 this->dirtyTypeMask();
reed@google.com8260a892011-06-13 14:02:52 +0000216}
217
msarettc1a3e242016-06-23 12:42:29 -0700218void SkMatrix44::set3x3RowMajorf(const float src[]) {
reed50d3b572016-05-03 12:13:21 -0700219 fMat[0][0] = src[0]; fMat[0][1] = src[3]; fMat[0][2] = src[6]; fMat[0][3] = 0;
220 fMat[1][0] = src[1]; fMat[1][1] = src[4]; fMat[1][2] = src[7]; fMat[1][3] = 0;
221 fMat[2][0] = src[2]; fMat[2][1] = src[5]; fMat[2][2] = src[8]; fMat[2][3] = 0;
222 fMat[3][0] = 0; fMat[3][1] = 0; fMat[3][2] = 0; fMat[3][3] = 1;
223 this->dirtyTypeMask();
224}
225
brianosmande68d6c2016-09-09 10:36:17 -0700226void SkMatrix44::set3x4RowMajorf(const float src[]) {
227 fMat[0][0] = src[0]; fMat[1][0] = src[1]; fMat[2][0] = src[2]; fMat[3][0] = src[3];
228 fMat[0][1] = src[4]; fMat[1][1] = src[5]; fMat[2][1] = src[6]; fMat[3][1] = src[7];
229 fMat[0][2] = src[8]; fMat[1][2] = src[9]; fMat[2][2] = src[10]; fMat[3][2] = src[11];
230 fMat[0][3] = 0; fMat[1][3] = 0; fMat[2][3] = 0; fMat[3][3] = 1;
msarett111a42d2016-06-22 08:18:54 -0700231 this->dirtyTypeMask();
232}
233
reed@google.com8260a892011-06-13 14:02:52 +0000234///////////////////////////////////////////////////////////////////////////////
235
reed@google.com99b5c7f2012-12-05 22:13:59 +0000236void SkMatrix44::setTranslate(SkMScalar dx, SkMScalar dy, SkMScalar dz) {
reed@google.com8260a892011-06-13 14:02:52 +0000237 this->setIdentity();
skia.committer@gmail.come659c2e2012-12-04 02:01:25 +0000238
reed@google.com99b5c7f2012-12-05 22:13:59 +0000239 if (!dx && !dy && !dz) {
240 return;
reed@google.com7d683352012-12-03 21:19:52 +0000241 }
skia.committer@gmail.com0264fb42012-12-06 02:01:25 +0000242
reed@google.com99b5c7f2012-12-05 22:13:59 +0000243 fMat[3][0] = dx;
244 fMat[3][1] = dy;
245 fMat[3][2] = dz;
246 this->setTypeMask(kTranslate_Mask);
reed@google.com8260a892011-06-13 14:02:52 +0000247}
248
249void SkMatrix44::preTranslate(SkMScalar dx, SkMScalar dy, SkMScalar dz) {
reed@google.com99b5c7f2012-12-05 22:13:59 +0000250 if (!dx && !dy && !dz) {
251 return;
252 }
253
reed@google.com99b5c7f2012-12-05 22:13:59 +0000254 for (int i = 0; i < 4; ++i) {
commit-bot@chromium.org658e28b2013-10-29 21:08:51 +0000255 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 +0000256 }
257 this->dirtyTypeMask();
reed@google.com8260a892011-06-13 14:02:52 +0000258}
259
260void SkMatrix44::postTranslate(SkMScalar dx, SkMScalar dy, SkMScalar dz) {
reed@google.com99b5c7f2012-12-05 22:13:59 +0000261 if (!dx && !dy && !dz) {
262 return;
263 }
264
265 if (this->getType() & kPerspective_Mask) {
266 for (int i = 0; i < 4; ++i) {
267 fMat[i][0] += fMat[i][3] * dx;
268 fMat[i][1] += fMat[i][3] * dy;
269 fMat[i][2] += fMat[i][3] * dz;
270 }
271 } else {
272 fMat[3][0] += dx;
273 fMat[3][1] += dy;
274 fMat[3][2] += dz;
275 this->dirtyTypeMask();
276 }
reed@google.com8260a892011-06-13 14:02:52 +0000277}
278
279///////////////////////////////////////////////////////////////////////////////
280
281void SkMatrix44::setScale(SkMScalar sx, SkMScalar sy, SkMScalar sz) {
reed@google.com99b5c7f2012-12-05 22:13:59 +0000282 this->setIdentity();
283
284 if (1 == sx && 1 == sy && 1 == sz) {
285 return;
286 }
287
reed@google.com8260a892011-06-13 14:02:52 +0000288 fMat[0][0] = sx;
289 fMat[1][1] = sy;
290 fMat[2][2] = sz;
reed@google.com99b5c7f2012-12-05 22:13:59 +0000291 this->setTypeMask(kScale_Mask);
reed@google.com8260a892011-06-13 14:02:52 +0000292}
293
294void SkMatrix44::preScale(SkMScalar sx, SkMScalar sy, SkMScalar sz) {
reed@google.com99b5c7f2012-12-05 22:13:59 +0000295 if (1 == sx && 1 == sy && 1 == sz) {
296 return;
297 }
skia.committer@gmail.com0264fb42012-12-06 02:01:25 +0000298
shawnsingh@chromium.orgf81f97e2012-12-13 22:21:36 +0000299 // The implementation matrix * pureScale can be shortcut
300 // by knowing that pureScale components effectively scale
301 // the columns of the original matrix.
302 for (int i = 0; i < 4; i++) {
303 fMat[0][i] *= sx;
304 fMat[1][i] *= sy;
305 fMat[2][i] *= sz;
306 }
307 this->dirtyTypeMask();
reed@google.com8260a892011-06-13 14:02:52 +0000308}
309
310void SkMatrix44::postScale(SkMScalar sx, SkMScalar sy, SkMScalar sz) {
reed@google.com99b5c7f2012-12-05 22:13:59 +0000311 if (1 == sx && 1 == sy && 1 == sz) {
312 return;
313 }
skia.committer@gmail.com0264fb42012-12-06 02:01:25 +0000314
reed@google.com8260a892011-06-13 14:02:52 +0000315 for (int i = 0; i < 4; i++) {
316 fMat[i][0] *= sx;
317 fMat[i][1] *= sy;
318 fMat[i][2] *= sz;
319 }
reed@google.com7d683352012-12-03 21:19:52 +0000320 this->dirtyTypeMask();
reed@google.com8260a892011-06-13 14:02:52 +0000321}
322
323///////////////////////////////////////////////////////////////////////////////
324
325void SkMatrix44::setRotateAbout(SkMScalar x, SkMScalar y, SkMScalar z,
326 SkMScalar radians) {
reed@google.com7d683352012-12-03 21:19:52 +0000327 double len2 = (double)x * x + (double)y * y + (double)z * z;
328 if (1 != len2) {
329 if (0 == len2) {
reed@google.com8260a892011-06-13 14:02:52 +0000330 this->setIdentity();
331 return;
332 }
333 double scale = 1 / sqrt(len2);
bsalomon@google.com9d12f5c2011-09-29 18:08:18 +0000334 x = SkDoubleToMScalar(x * scale);
335 y = SkDoubleToMScalar(y * scale);
336 z = SkDoubleToMScalar(z * scale);
reed@google.com8260a892011-06-13 14:02:52 +0000337 }
338 this->setRotateAboutUnit(x, y, z, radians);
339}
340
341void SkMatrix44::setRotateAboutUnit(SkMScalar x, SkMScalar y, SkMScalar z,
342 SkMScalar radians) {
343 double c = cos(radians);
344 double s = sin(radians);
345 double C = 1 - c;
346 double xs = x * s;
347 double ys = y * s;
348 double zs = z * s;
349 double xC = x * C;
350 double yC = y * C;
351 double zC = z * C;
352 double xyC = x * yC;
353 double yzC = y * zC;
354 double zxC = z * xC;
355
356 // if you're looking at wikipedia, remember that we're column major.
bsalomon@google.com9d12f5c2011-09-29 18:08:18 +0000357 this->set3x3(SkDoubleToMScalar(x * xC + c), // scale x
358 SkDoubleToMScalar(xyC + zs), // skew x
359 SkDoubleToMScalar(zxC - ys), // trans x
360
361 SkDoubleToMScalar(xyC - zs), // skew y
362 SkDoubleToMScalar(y * yC + c), // scale y
363 SkDoubleToMScalar(yzC + xs), // trans y
364
365 SkDoubleToMScalar(zxC + ys), // persp x
366 SkDoubleToMScalar(yzC - xs), // persp y
367 SkDoubleToMScalar(z * zC + c)); // persp 2
reed@google.com8260a892011-06-13 14:02:52 +0000368}
369
370///////////////////////////////////////////////////////////////////////////////
371
reed@google.com99b5c7f2012-12-05 22:13:59 +0000372static bool bits_isonly(int value, int mask) {
373 return 0 == (value & ~mask);
374}
375
reed@google.com8260a892011-06-13 14:02:52 +0000376void SkMatrix44::setConcat(const SkMatrix44& a, const SkMatrix44& b) {
reed@google.com99b5c7f2012-12-05 22:13:59 +0000377 const SkMatrix44::TypeMask a_mask = a.getType();
378 const SkMatrix44::TypeMask b_mask = b.getType();
379
380 if (kIdentity_Mask == a_mask) {
reed@google.com7d683352012-12-03 21:19:52 +0000381 *this = b;
382 return;
383 }
reed@google.com99b5c7f2012-12-05 22:13:59 +0000384 if (kIdentity_Mask == b_mask) {
reed@google.com7d683352012-12-03 21:19:52 +0000385 *this = a;
386 return;
387 }
388
389 bool useStorage = (this == &a || this == &b);
390 SkMScalar storage[16];
391 SkMScalar* result = useStorage ? storage : &fMat[0][0];
392
reed@google.com2b165702013-01-17 16:01:19 +0000393 // Both matrices are at most scale+translate
reed@google.com99b5c7f2012-12-05 22:13:59 +0000394 if (bits_isonly(a_mask | b_mask, kScale_Mask | kTranslate_Mask)) {
reed@google.com99b5c7f2012-12-05 22:13:59 +0000395 result[0] = a.fMat[0][0] * b.fMat[0][0];
reed@google.com2b165702013-01-17 16:01:19 +0000396 result[1] = result[2] = result[3] = result[4] = 0;
reed@google.com99b5c7f2012-12-05 22:13:59 +0000397 result[5] = a.fMat[1][1] * b.fMat[1][1];
reed@google.com2b165702013-01-17 16:01:19 +0000398 result[6] = result[7] = result[8] = result[9] = 0;
reed@google.com99b5c7f2012-12-05 22:13:59 +0000399 result[10] = a.fMat[2][2] * b.fMat[2][2];
reed@google.com2b165702013-01-17 16:01:19 +0000400 result[11] = 0;
reed@google.com99b5c7f2012-12-05 22:13:59 +0000401 result[12] = a.fMat[0][0] * b.fMat[3][0] + a.fMat[3][0];
402 result[13] = a.fMat[1][1] * b.fMat[3][1] + a.fMat[3][1];
403 result[14] = a.fMat[2][2] * b.fMat[3][2] + a.fMat[3][2];
404 result[15] = 1;
405 } else {
406 for (int j = 0; j < 4; j++) {
407 for (int i = 0; i < 4; i++) {
commit-bot@chromium.orgbde4ba22014-01-24 18:48:00 +0000408 double value = 0;
reed@google.com99b5c7f2012-12-05 22:13:59 +0000409 for (int k = 0; k < 4; k++) {
commit-bot@chromium.orgbde4ba22014-01-24 18:48:00 +0000410 value += SkMScalarToDouble(a.fMat[k][i]) * b.fMat[j][k];
reed@google.com99b5c7f2012-12-05 22:13:59 +0000411 }
commit-bot@chromium.orgbde4ba22014-01-24 18:48:00 +0000412 *result++ = SkDoubleToMScalar(value);
reed@google.com8260a892011-06-13 14:02:52 +0000413 }
reed@google.com8260a892011-06-13 14:02:52 +0000414 }
415 }
reed@google.com99b5c7f2012-12-05 22:13:59 +0000416
reed@google.com7d683352012-12-03 21:19:52 +0000417 if (useStorage) {
tomhudson@google.com7cfb9c72013-01-17 13:29:35 +0000418 memcpy(fMat, storage, sizeof(storage));
reed@google.com7d683352012-12-03 21:19:52 +0000419 }
reed@google.com7d683352012-12-03 21:19:52 +0000420 this->dirtyTypeMask();
reed@google.com8260a892011-06-13 14:02:52 +0000421}
422
423///////////////////////////////////////////////////////////////////////////////
424
reed@google.com8260a892011-06-13 14:02:52 +0000425/** We always perform the calculation in doubles, to avoid prematurely losing
426 precision along the way. This relies on the compiler automatically
427 promoting our SkMScalar values to double (if needed).
428 */
429double SkMatrix44::determinant() const {
mike@reedtribe.orgf8b1ebc2012-12-10 03:27:47 +0000430 if (this->isIdentity()) {
431 return 1;
432 }
433 if (this->isScaleTranslate()) {
434 return fMat[0][0] * fMat[1][1] * fMat[2][2] * fMat[3][3];
435 }
436
tomhudson@google.com9973a8a2012-12-13 09:55:42 +0000437 double a00 = fMat[0][0];
438 double a01 = fMat[0][1];
439 double a02 = fMat[0][2];
440 double a03 = fMat[0][3];
441 double a10 = fMat[1][0];
442 double a11 = fMat[1][1];
443 double a12 = fMat[1][2];
444 double a13 = fMat[1][3];
445 double a20 = fMat[2][0];
446 double a21 = fMat[2][1];
447 double a22 = fMat[2][2];
448 double a23 = fMat[2][3];
449 double a30 = fMat[3][0];
450 double a31 = fMat[3][1];
451 double a32 = fMat[3][2];
452 double a33 = fMat[3][3];
453
454 double b00 = a00 * a11 - a01 * a10;
455 double b01 = a00 * a12 - a02 * a10;
456 double b02 = a00 * a13 - a03 * a10;
457 double b03 = a01 * a12 - a02 * a11;
458 double b04 = a01 * a13 - a03 * a11;
459 double b05 = a02 * a13 - a03 * a12;
460 double b06 = a20 * a31 - a21 * a30;
461 double b07 = a20 * a32 - a22 * a30;
462 double b08 = a20 * a33 - a23 * a30;
463 double b09 = a21 * a32 - a22 * a31;
464 double b10 = a21 * a33 - a23 * a31;
465 double b11 = a22 * a33 - a23 * a32;
466
467 // Calculate the determinant
468 return b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
reed@google.com8260a892011-06-13 14:02:52 +0000469}
470
471///////////////////////////////////////////////////////////////////////////////
472
vmpstra8d45592015-06-30 13:36:04 -0700473static bool is_matrix_finite(const SkMatrix44& matrix) {
474 SkMScalar accumulator = 0;
475 for (int row = 0; row < 4; ++row) {
476 for (int col = 0; col < 4; ++col) {
477 accumulator *= matrix.get(row, col);
478 }
479 }
480 return accumulator == 0;
481}
482
483bool SkMatrix44::invert(SkMatrix44* storage) const {
mike@reedtribe.orgf8b1ebc2012-12-10 03:27:47 +0000484 if (this->isIdentity()) {
vmpstra8d45592015-06-30 13:36:04 -0700485 if (storage) {
486 storage->setIdentity();
reed@google.com7d683352012-12-03 21:19:52 +0000487 }
commit-bot@chromium.org178acd22013-11-20 21:32:27 +0000488 return true;
reed@google.com7d683352012-12-03 21:19:52 +0000489 }
commit-bot@chromium.org178acd22013-11-20 21:32:27 +0000490
mike@reedtribe.orgf8b1ebc2012-12-10 03:27:47 +0000491 if (this->isTranslate()) {
vmpstra8d45592015-06-30 13:36:04 -0700492 if (storage) {
493 storage->setTranslate(-fMat[3][0], -fMat[3][1], -fMat[3][2]);
reed@google.com99b5c7f2012-12-05 22:13:59 +0000494 }
495 return true;
496 }
commit-bot@chromium.org178acd22013-11-20 21:32:27 +0000497
vmpstra8d45592015-06-30 13:36:04 -0700498 SkMatrix44 tmp(kUninitialized_Constructor);
499 // Use storage if it's available and distinct from this matrix.
500 SkMatrix44* inverse = (storage && storage != this) ? storage : &tmp;
mike@reedtribe.orgf8b1ebc2012-12-10 03:27:47 +0000501 if (this->isScaleTranslate()) {
reed@google.com99b5c7f2012-12-05 22:13:59 +0000502 if (0 == fMat[0][0] * fMat[1][1] * fMat[2][2]) {
503 return false;
504 }
reed@google.com99b5c7f2012-12-05 22:13:59 +0000505
vmpstra8d45592015-06-30 13:36:04 -0700506 double invXScale = 1 / fMat[0][0];
507 double invYScale = 1 / fMat[1][1];
508 double invZScale = 1 / fMat[2][2];
reed@google.com99b5c7f2012-12-05 22:13:59 +0000509
vmpstra8d45592015-06-30 13:36:04 -0700510 inverse->fMat[0][0] = SkDoubleToMScalar(invXScale);
511 inverse->fMat[0][1] = 0;
512 inverse->fMat[0][2] = 0;
513 inverse->fMat[0][3] = 0;
skia.committer@gmail.com772c4e62013-08-30 07:01:34 +0000514
vmpstra8d45592015-06-30 13:36:04 -0700515 inverse->fMat[1][0] = 0;
516 inverse->fMat[1][1] = SkDoubleToMScalar(invYScale);
517 inverse->fMat[1][2] = 0;
518 inverse->fMat[1][3] = 0;
skia.committer@gmail.com772c4e62013-08-30 07:01:34 +0000519
vmpstra8d45592015-06-30 13:36:04 -0700520 inverse->fMat[2][0] = 0;
521 inverse->fMat[2][1] = 0;
522 inverse->fMat[2][2] = SkDoubleToMScalar(invZScale);
523 inverse->fMat[2][3] = 0;
skia.committer@gmail.com772c4e62013-08-30 07:01:34 +0000524
vmpstra8d45592015-06-30 13:36:04 -0700525 inverse->fMat[3][0] = SkDoubleToMScalar(-fMat[3][0] * invXScale);
526 inverse->fMat[3][1] = SkDoubleToMScalar(-fMat[3][1] * invYScale);
527 inverse->fMat[3][2] = SkDoubleToMScalar(-fMat[3][2] * invZScale);
528 inverse->fMat[3][3] = 1;
shawnsingh@chromium.orgb6823c12013-08-22 20:24:21 +0000529
vmpstra8d45592015-06-30 13:36:04 -0700530 inverse->setTypeMask(this->getType());
531
532 if (!is_matrix_finite(*inverse)) {
533 return false;
shawnsingh@chromium.org5a6cd352013-08-28 18:55:25 +0000534 }
vmpstra8d45592015-06-30 13:36:04 -0700535 if (storage && inverse != storage) {
536 *storage = *inverse;
537 }
reed@google.com99b5c7f2012-12-05 22:13:59 +0000538 return true;
539 }
540
tomhudson@google.com9973a8a2012-12-13 09:55:42 +0000541 double a00 = fMat[0][0];
542 double a01 = fMat[0][1];
543 double a02 = fMat[0][2];
544 double a03 = fMat[0][3];
545 double a10 = fMat[1][0];
546 double a11 = fMat[1][1];
547 double a12 = fMat[1][2];
548 double a13 = fMat[1][3];
549 double a20 = fMat[2][0];
550 double a21 = fMat[2][1];
551 double a22 = fMat[2][2];
552 double a23 = fMat[2][3];
553 double a30 = fMat[3][0];
554 double a31 = fMat[3][1];
555 double a32 = fMat[3][2];
556 double a33 = fMat[3][3];
557
shawnsingh@chromium.orgb6823c12013-08-22 20:24:21 +0000558 if (!(this->getType() & kPerspective_Mask)) {
559 // If we know the matrix has no perspective, then the perspective
560 // component is (0, 0, 0, 1). We can use this information to save a lot
561 // of arithmetic that would otherwise be spent to compute the inverse
562 // of a general matrix.
563
564 SkASSERT(a03 == 0);
565 SkASSERT(a13 == 0);
566 SkASSERT(a23 == 0);
567 SkASSERT(a33 == 1);
568
569 double b00 = a00 * a11 - a01 * a10;
570 double b01 = a00 * a12 - a02 * a10;
571 double b03 = a01 * a12 - a02 * a11;
572 double b06 = a20 * a31 - a21 * a30;
573 double b07 = a20 * a32 - a22 * a30;
574 double b08 = a20;
575 double b09 = a21 * a32 - a22 * a31;
576 double b10 = a21;
577 double b11 = a22;
578
579 // Calculate the determinant
580 double det = b00 * b11 - b01 * b10 + b03 * b08;
581
582 double invdet = 1.0 / det;
583 // If det is zero, we want to return false. However, we also want to return false
584 // if 1/det overflows to infinity (i.e. det is denormalized). Both of these are
585 // handled by checking that 1/det is finite.
586 if (!sk_float_isfinite(invdet)) {
587 return false;
588 }
shawnsingh@chromium.orgb6823c12013-08-22 20:24:21 +0000589
590 b00 *= invdet;
591 b01 *= invdet;
592 b03 *= invdet;
593 b06 *= invdet;
594 b07 *= invdet;
595 b08 *= invdet;
596 b09 *= invdet;
597 b10 *= invdet;
598 b11 *= invdet;
599
600 inverse->fMat[0][0] = SkDoubleToMScalar(a11 * b11 - a12 * b10);
601 inverse->fMat[0][1] = SkDoubleToMScalar(a02 * b10 - a01 * b11);
602 inverse->fMat[0][2] = SkDoubleToMScalar(b03);
603 inverse->fMat[0][3] = 0;
604 inverse->fMat[1][0] = SkDoubleToMScalar(a12 * b08 - a10 * b11);
605 inverse->fMat[1][1] = SkDoubleToMScalar(a00 * b11 - a02 * b08);
606 inverse->fMat[1][2] = SkDoubleToMScalar(-b01);
607 inverse->fMat[1][3] = 0;
608 inverse->fMat[2][0] = SkDoubleToMScalar(a10 * b10 - a11 * b08);
609 inverse->fMat[2][1] = SkDoubleToMScalar(a01 * b08 - a00 * b10);
610 inverse->fMat[2][2] = SkDoubleToMScalar(b00);
611 inverse->fMat[2][3] = 0;
612 inverse->fMat[3][0] = SkDoubleToMScalar(a11 * b07 - a10 * b09 - a12 * b06);
613 inverse->fMat[3][1] = SkDoubleToMScalar(a00 * b09 - a01 * b07 + a02 * b06);
614 inverse->fMat[3][2] = SkDoubleToMScalar(a31 * b01 - a30 * b03 - a32 * b00);
615 inverse->fMat[3][3] = 1;
616
617 inverse->setTypeMask(this->getType());
vmpstra8d45592015-06-30 13:36:04 -0700618 if (!is_matrix_finite(*inverse)) {
619 return false;
620 }
621 if (storage && inverse != storage) {
622 *storage = *inverse;
623 }
shawnsingh@chromium.orgb6823c12013-08-22 20:24:21 +0000624 return true;
625 }
626
tomhudson@google.com9973a8a2012-12-13 09:55:42 +0000627 double b00 = a00 * a11 - a01 * a10;
628 double b01 = a00 * a12 - a02 * a10;
629 double b02 = a00 * a13 - a03 * a10;
630 double b03 = a01 * a12 - a02 * a11;
631 double b04 = a01 * a13 - a03 * a11;
632 double b05 = a02 * a13 - a03 * a12;
633 double b06 = a20 * a31 - a21 * a30;
634 double b07 = a20 * a32 - a22 * a30;
635 double b08 = a20 * a33 - a23 * a30;
636 double b09 = a21 * a32 - a22 * a31;
637 double b10 = a21 * a33 - a23 * a31;
638 double b11 = a22 * a33 - a23 * a32;
639
640 // Calculate the determinant
641 double det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
642
commit-bot@chromium.orgf02f0782013-08-20 15:25:04 +0000643 double invdet = 1.0 / det;
644 // If det is zero, we want to return false. However, we also want to return false
645 // if 1/det overflows to infinity (i.e. det is denormalized). Both of these are
646 // handled by checking that 1/det is finite.
647 if (!sk_float_isfinite(invdet)) {
reed@google.com8260a892011-06-13 14:02:52 +0000648 return false;
649 }
reed@google.com8260a892011-06-13 14:02:52 +0000650
tomhudson@google.com9973a8a2012-12-13 09:55:42 +0000651 b00 *= invdet;
652 b01 *= invdet;
653 b02 *= invdet;
654 b03 *= invdet;
655 b04 *= invdet;
656 b05 *= invdet;
657 b06 *= invdet;
658 b07 *= invdet;
659 b08 *= invdet;
660 b09 *= invdet;
661 b10 *= invdet;
662 b11 *= invdet;
reed@google.com8260a892011-06-13 14:02:52 +0000663
tomhudson@google.com9973a8a2012-12-13 09:55:42 +0000664 inverse->fMat[0][0] = SkDoubleToMScalar(a11 * b11 - a12 * b10 + a13 * b09);
665 inverse->fMat[0][1] = SkDoubleToMScalar(a02 * b10 - a01 * b11 - a03 * b09);
666 inverse->fMat[0][2] = SkDoubleToMScalar(a31 * b05 - a32 * b04 + a33 * b03);
667 inverse->fMat[0][3] = SkDoubleToMScalar(a22 * b04 - a21 * b05 - a23 * b03);
668 inverse->fMat[1][0] = SkDoubleToMScalar(a12 * b08 - a10 * b11 - a13 * b07);
669 inverse->fMat[1][1] = SkDoubleToMScalar(a00 * b11 - a02 * b08 + a03 * b07);
670 inverse->fMat[1][2] = SkDoubleToMScalar(a32 * b02 - a30 * b05 - a33 * b01);
671 inverse->fMat[1][3] = SkDoubleToMScalar(a20 * b05 - a22 * b02 + a23 * b01);
672 inverse->fMat[2][0] = SkDoubleToMScalar(a10 * b10 - a11 * b08 + a13 * b06);
673 inverse->fMat[2][1] = SkDoubleToMScalar(a01 * b08 - a00 * b10 - a03 * b06);
674 inverse->fMat[2][2] = SkDoubleToMScalar(a30 * b04 - a31 * b02 + a33 * b00);
675 inverse->fMat[2][3] = SkDoubleToMScalar(a21 * b02 - a20 * b04 - a23 * b00);
676 inverse->fMat[3][0] = SkDoubleToMScalar(a11 * b07 - a10 * b09 - a12 * b06);
677 inverse->fMat[3][1] = SkDoubleToMScalar(a00 * b09 - a01 * b07 + a02 * b06);
678 inverse->fMat[3][2] = SkDoubleToMScalar(a31 * b01 - a30 * b03 - a32 * b00);
679 inverse->fMat[3][3] = SkDoubleToMScalar(a20 * b03 - a21 * b01 + a22 * b00);
680 inverse->dirtyTypeMask();
reed@google.com8260a892011-06-13 14:02:52 +0000681
vmpstra8d45592015-06-30 13:36:04 -0700682 inverse->setTypeMask(this->getType());
683 if (!is_matrix_finite(*inverse)) {
684 return false;
685 }
686 if (storage && inverse != storage) {
687 *storage = *inverse;
688 }
reed@google.com8260a892011-06-13 14:02:52 +0000689 return true;
690}
691
692///////////////////////////////////////////////////////////////////////////////
693
vollick@chromium.org9b21c252012-11-14 21:33:55 +0000694void SkMatrix44::transpose() {
695 SkTSwap(fMat[0][1], fMat[1][0]);
696 SkTSwap(fMat[0][2], fMat[2][0]);
697 SkTSwap(fMat[0][3], fMat[3][0]);
698 SkTSwap(fMat[1][2], fMat[2][1]);
699 SkTSwap(fMat[1][3], fMat[3][1]);
700 SkTSwap(fMat[2][3], fMat[3][2]);
reed@google.com7d683352012-12-03 21:19:52 +0000701
702 if (!this->isTriviallyIdentity()) {
703 this->dirtyTypeMask();
704 }
vollick@chromium.org9b21c252012-11-14 21:33:55 +0000705}
706
707///////////////////////////////////////////////////////////////////////////////
708
reed@google.com1ea95be2012-11-09 21:39:48 +0000709void SkMatrix44::mapScalars(const SkScalar src[4], SkScalar dst[4]) const {
reed@google.com7d683352012-12-03 21:19:52 +0000710 SkScalar storage[4];
711 SkScalar* result = (src == dst) ? storage : dst;
712
reed@google.com8260a892011-06-13 14:02:52 +0000713 for (int i = 0; i < 4; i++) {
714 SkMScalar value = 0;
715 for (int j = 0; j < 4; j++) {
716 value += fMat[j][i] * src[j];
717 }
bsalomon@google.com72e49b82011-10-27 21:47:03 +0000718 result[i] = SkMScalarToScalar(value);
reed@google.com8260a892011-06-13 14:02:52 +0000719 }
skia.committer@gmail.com0264fb42012-12-06 02:01:25 +0000720
reed@google.com7d683352012-12-03 21:19:52 +0000721 if (storage == result) {
722 memcpy(dst, storage, sizeof(storage));
723 }
reed@google.com8260a892011-06-13 14:02:52 +0000724}
725
reed@google.com1ea95be2012-11-09 21:39:48 +0000726#ifdef SK_MSCALAR_IS_DOUBLE
reed@google.com7d683352012-12-03 21:19:52 +0000727
reed@google.com1ea95be2012-11-09 21:39:48 +0000728void SkMatrix44::mapMScalars(const SkMScalar src[4], SkMScalar dst[4]) const {
reed@google.com7d683352012-12-03 21:19:52 +0000729 SkMScalar storage[4];
730 SkMScalar* result = (src == dst) ? storage : dst;
skia.committer@gmail.com0264fb42012-12-06 02:01:25 +0000731
reed@google.com1ea95be2012-11-09 21:39:48 +0000732 for (int i = 0; i < 4; i++) {
733 SkMScalar value = 0;
734 for (int j = 0; j < 4; j++) {
735 value += fMat[j][i] * src[j];
736 }
reed@google.com7d683352012-12-03 21:19:52 +0000737 result[i] = value;
reed@google.com1ea95be2012-11-09 21:39:48 +0000738 }
skia.committer@gmail.com0264fb42012-12-06 02:01:25 +0000739
reed@google.com7d683352012-12-03 21:19:52 +0000740 if (storage == result) {
741 memcpy(dst, storage, sizeof(storage));
742 }
reed@google.com1ea95be2012-11-09 21:39:48 +0000743}
reed@google.com7d683352012-12-03 21:19:52 +0000744
reed@google.com1ea95be2012-11-09 21:39:48 +0000745#endif
746
reed@google.com99b5c7f2012-12-05 22:13:59 +0000747typedef void (*Map2Procf)(const SkMScalar mat[][4], const float src2[], int count, float dst4[]);
748typedef void (*Map2Procd)(const SkMScalar mat[][4], const double src2[], int count, double dst4[]);
749
750static void map2_if(const SkMScalar mat[][4], const float* SK_RESTRICT src2,
751 int count, float* SK_RESTRICT dst4) {
752 for (int i = 0; i < count; ++i) {
753 dst4[0] = src2[0];
754 dst4[1] = src2[1];
755 dst4[2] = 0;
756 dst4[3] = 1;
757 src2 += 2;
758 dst4 += 4;
759 }
760}
761
762static void map2_id(const SkMScalar mat[][4], const double* SK_RESTRICT src2,
763 int count, double* SK_RESTRICT dst4) {
764 for (int i = 0; i < count; ++i) {
765 dst4[0] = src2[0];
766 dst4[1] = src2[1];
767 dst4[2] = 0;
768 dst4[3] = 1;
769 src2 += 2;
770 dst4 += 4;
771 }
772}
773
774static void map2_tf(const SkMScalar mat[][4], const float* SK_RESTRICT src2,
775 int count, float* SK_RESTRICT dst4) {
776 const float mat30 = SkMScalarToFloat(mat[3][0]);
777 const float mat31 = SkMScalarToFloat(mat[3][1]);
778 const float mat32 = SkMScalarToFloat(mat[3][2]);
779 for (int n = 0; n < count; ++n) {
780 dst4[0] = src2[0] + mat30;
781 dst4[1] = src2[1] + mat31;
782 dst4[2] = mat32;
783 dst4[3] = 1;
784 src2 += 2;
785 dst4 += 4;
786 }
787}
788
789static void map2_td(const SkMScalar mat[][4], const double* SK_RESTRICT src2,
790 int count, double* SK_RESTRICT dst4) {
791 for (int n = 0; n < count; ++n) {
792 dst4[0] = src2[0] + mat[3][0];
793 dst4[1] = src2[1] + mat[3][1];
794 dst4[2] = mat[3][2];
795 dst4[3] = 1;
796 src2 += 2;
797 dst4 += 4;
798 }
799}
800
801static void map2_sf(const SkMScalar mat[][4], const float* SK_RESTRICT src2,
802 int count, float* SK_RESTRICT dst4) {
803 const float mat32 = SkMScalarToFloat(mat[3][2]);
804 for (int n = 0; n < count; ++n) {
805 dst4[0] = SkMScalarToFloat(mat[0][0] * src2[0] + mat[3][0]);
806 dst4[1] = SkMScalarToFloat(mat[1][1] * src2[1] + mat[3][1]);
807 dst4[2] = mat32;
808 dst4[3] = 1;
809 src2 += 2;
810 dst4 += 4;
811 }
812}
813
814static void map2_sd(const SkMScalar mat[][4], const double* SK_RESTRICT src2,
815 int count, double* SK_RESTRICT dst4) {
816 for (int n = 0; n < count; ++n) {
817 dst4[0] = mat[0][0] * src2[0] + mat[3][0];
818 dst4[1] = mat[1][1] * src2[1] + mat[3][1];
819 dst4[2] = mat[3][2];
820 dst4[3] = 1;
821 src2 += 2;
822 dst4 += 4;
823 }
824}
825
826static void map2_af(const SkMScalar mat[][4], const float* SK_RESTRICT src2,
827 int count, float* SK_RESTRICT dst4) {
commit-bot@chromium.org658e28b2013-10-29 21:08:51 +0000828 SkMScalar r;
reed@google.com99b5c7f2012-12-05 22:13:59 +0000829 for (int n = 0; n < count; ++n) {
commit-bot@chromium.org658e28b2013-10-29 21:08:51 +0000830 SkMScalar sx = SkFloatToMScalar(src2[0]);
831 SkMScalar sy = SkFloatToMScalar(src2[1]);
reed@google.com99b5c7f2012-12-05 22:13:59 +0000832 r = mat[0][0] * sx + mat[1][0] * sy + mat[3][0];
833 dst4[0] = SkMScalarToFloat(r);
834 r = mat[0][1] * sx + mat[1][1] * sy + mat[3][1];
835 dst4[1] = SkMScalarToFloat(r);
836 r = mat[0][2] * sx + mat[1][2] * sy + mat[3][2];
837 dst4[2] = SkMScalarToFloat(r);
838 dst4[3] = 1;
839 src2 += 2;
840 dst4 += 4;
841 }
842}
843
844static void map2_ad(const SkMScalar mat[][4], const double* SK_RESTRICT src2,
845 int count, double* SK_RESTRICT dst4) {
846 for (int n = 0; n < count; ++n) {
847 double sx = src2[0];
848 double sy = src2[1];
849 dst4[0] = mat[0][0] * sx + mat[1][0] * sy + mat[3][0];
850 dst4[1] = mat[0][1] * sx + mat[1][1] * sy + mat[3][1];
851 dst4[2] = mat[0][2] * sx + mat[1][2] * sy + mat[3][2];
852 dst4[3] = 1;
853 src2 += 2;
854 dst4 += 4;
855 }
856}
857
858static void map2_pf(const SkMScalar mat[][4], const float* SK_RESTRICT src2,
859 int count, float* SK_RESTRICT dst4) {
commit-bot@chromium.org658e28b2013-10-29 21:08:51 +0000860 SkMScalar r;
reed@google.com99b5c7f2012-12-05 22:13:59 +0000861 for (int n = 0; n < count; ++n) {
commit-bot@chromium.org658e28b2013-10-29 21:08:51 +0000862 SkMScalar sx = SkFloatToMScalar(src2[0]);
863 SkMScalar sy = SkFloatToMScalar(src2[1]);
reed@google.com99b5c7f2012-12-05 22:13:59 +0000864 for (int i = 0; i < 4; i++) {
commit-bot@chromium.org658e28b2013-10-29 21:08:51 +0000865 r = mat[0][i] * sx + mat[1][i] * sy + mat[3][i];
866 dst4[i] = SkMScalarToFloat(r);
reed@google.com99b5c7f2012-12-05 22:13:59 +0000867 }
868 src2 += 2;
869 dst4 += 4;
870 }
871}
872
873static void map2_pd(const SkMScalar mat[][4], const double* SK_RESTRICT src2,
874 int count, double* SK_RESTRICT dst4) {
875 for (int n = 0; n < count; ++n) {
876 double sx = src2[0];
877 double sy = src2[1];
878 for (int i = 0; i < 4; i++) {
879 dst4[i] = mat[0][i] * sx + mat[1][i] * sy + mat[3][i];
880 }
881 src2 += 2;
882 dst4 += 4;
883 }
884}
885
886void SkMatrix44::map2(const float src2[], int count, float dst4[]) const {
887 static const Map2Procf gProc[] = {
888 map2_if, map2_tf, map2_sf, map2_sf, map2_af, map2_af, map2_af, map2_af
889 };
890
891 TypeMask mask = this->getType();
892 Map2Procf proc = (mask & kPerspective_Mask) ? map2_pf : gProc[mask];
893 proc(fMat, src2, count, dst4);
894}
895
896void SkMatrix44::map2(const double src2[], int count, double dst4[]) const {
897 static const Map2Procd gProc[] = {
898 map2_id, map2_td, map2_sd, map2_sd, map2_ad, map2_ad, map2_ad, map2_ad
899 };
skia.committer@gmail.com0264fb42012-12-06 02:01:25 +0000900
reed@google.com99b5c7f2012-12-05 22:13:59 +0000901 TypeMask mask = this->getType();
902 Map2Procd proc = (mask & kPerspective_Mask) ? map2_pd : gProc[mask];
903 proc(fMat, src2, count, dst4);
904}
905
tomhudsonfaccb8e2014-09-26 11:45:48 -0700906bool SkMatrix44::preserves2dAxisAlignment (SkMScalar epsilon) const {
907
908 // Can't check (mask & kPerspective_Mask) because Z isn't relevant here.
909 if (0 != perspX() || 0 != perspY()) return false;
910
911 // A matrix with two non-zeroish values in any of the upper right
912 // rows or columns will skew. If only one value in each row or
913 // column is non-zeroish, we get a scale plus perhaps a 90-degree
914 // rotation.
915 int col0 = 0;
916 int col1 = 0;
917 int row0 = 0;
918 int row1 = 0;
919
920 // Must test against epsilon, not 0, because we can get values
921 // around 6e-17 in the matrix that "should" be 0.
922
923 if (SkMScalarAbs(fMat[0][0]) > epsilon) {
924 col0++;
925 row0++;
926 }
927 if (SkMScalarAbs(fMat[0][1]) > epsilon) {
928 col1++;
929 row0++;
930 }
931 if (SkMScalarAbs(fMat[1][0]) > epsilon) {
932 col0++;
933 row1++;
934 }
935 if (SkMScalarAbs(fMat[1][1]) > epsilon) {
936 col1++;
937 row1++;
938 }
939 if (col0 > 1 || col1 > 1 || row0 > 1 || row1 > 1) {
940 return false;
941 }
942
943 return true;
944}
945
reed@google.com8260a892011-06-13 14:02:52 +0000946///////////////////////////////////////////////////////////////////////////////
947
948void SkMatrix44::dump() const {
tomhudson@google.com9ac4a892011-06-28 13:53:13 +0000949 static const char* format =
950 "[%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 +0000951#if 0
tomhudson@google.com9ac4a892011-06-28 13:53:13 +0000952 SkDebugf(format,
reed@google.com8260a892011-06-13 14:02:52 +0000953 fMat[0][0], fMat[1][0], fMat[2][0], fMat[3][0],
954 fMat[0][1], fMat[1][1], fMat[2][1], fMat[3][1],
955 fMat[0][2], fMat[1][2], fMat[2][2], fMat[3][2],
956 fMat[0][3], fMat[1][3], fMat[2][3], fMat[3][3]);
tomhudson@google.com9ac4a892011-06-28 13:53:13 +0000957#else
958 SkDebugf(format,
959 fMat[0][0], fMat[0][1], fMat[0][2], fMat[0][3],
960 fMat[1][0], fMat[1][1], fMat[1][2], fMat[1][3],
961 fMat[2][0], fMat[2][1], fMat[2][2], fMat[2][3],
962 fMat[3][0], fMat[3][1], fMat[3][2], fMat[3][3]);
reed@google.com8260a892011-06-13 14:02:52 +0000963#endif
964}
965
966///////////////////////////////////////////////////////////////////////////////
967
968static void initFromMatrix(SkMScalar dst[4][4], const SkMatrix& src) {
bsalomon@google.com72e49b82011-10-27 21:47:03 +0000969 dst[0][0] = SkScalarToMScalar(src[SkMatrix::kMScaleX]);
970 dst[1][0] = SkScalarToMScalar(src[SkMatrix::kMSkewX]);
shawnsingh@chromium.org5a6cd352013-08-28 18:55:25 +0000971 dst[2][0] = 0;
bsalomon@google.com72e49b82011-10-27 21:47:03 +0000972 dst[3][0] = SkScalarToMScalar(src[SkMatrix::kMTransX]);
973 dst[0][1] = SkScalarToMScalar(src[SkMatrix::kMSkewY]);
974 dst[1][1] = SkScalarToMScalar(src[SkMatrix::kMScaleY]);
shawnsingh@chromium.org5a6cd352013-08-28 18:55:25 +0000975 dst[2][1] = 0;
bsalomon@google.com72e49b82011-10-27 21:47:03 +0000976 dst[3][1] = SkScalarToMScalar(src[SkMatrix::kMTransY]);
shawnsingh@chromium.org5a6cd352013-08-28 18:55:25 +0000977 dst[0][2] = 0;
978 dst[1][2] = 0;
979 dst[2][2] = 1;
980 dst[3][2] = 0;
commit-bot@chromium.org722555b2013-10-05 01:16:30 +0000981 dst[0][3] = SkScalarToMScalar(src[SkMatrix::kMPersp0]);
982 dst[1][3] = SkScalarToMScalar(src[SkMatrix::kMPersp1]);
shawnsingh@chromium.org5a6cd352013-08-28 18:55:25 +0000983 dst[2][3] = 0;
commit-bot@chromium.org722555b2013-10-05 01:16:30 +0000984 dst[3][3] = SkScalarToMScalar(src[SkMatrix::kMPersp2]);
reed@google.com8260a892011-06-13 14:02:52 +0000985}
986
987SkMatrix44::SkMatrix44(const SkMatrix& src) {
fs88640cf2014-12-16 08:36:11 -0800988 this->operator=(src);
reed@google.com8260a892011-06-13 14:02:52 +0000989}
990
991SkMatrix44& SkMatrix44::operator=(const SkMatrix& src) {
992 initFromMatrix(fMat, src);
reed@google.com7d683352012-12-03 21:19:52 +0000993
994 if (src.isIdentity()) {
995 this->setTypeMask(kIdentity_Mask);
996 } else {
997 this->dirtyTypeMask();
998 }
reed@google.com8260a892011-06-13 14:02:52 +0000999 return *this;
1000}
1001
1002SkMatrix44::operator SkMatrix() const {
1003 SkMatrix dst;
reed@google.com8260a892011-06-13 14:02:52 +00001004
bsalomon@google.com72e49b82011-10-27 21:47:03 +00001005 dst[SkMatrix::kMScaleX] = SkMScalarToScalar(fMat[0][0]);
1006 dst[SkMatrix::kMSkewX] = SkMScalarToScalar(fMat[1][0]);
1007 dst[SkMatrix::kMTransX] = SkMScalarToScalar(fMat[3][0]);
reed@google.com8260a892011-06-13 14:02:52 +00001008
bsalomon@google.com72e49b82011-10-27 21:47:03 +00001009 dst[SkMatrix::kMSkewY] = SkMScalarToScalar(fMat[0][1]);
1010 dst[SkMatrix::kMScaleY] = SkMScalarToScalar(fMat[1][1]);
1011 dst[SkMatrix::kMTransY] = SkMScalarToScalar(fMat[3][1]);
reed@google.com8260a892011-06-13 14:02:52 +00001012
commit-bot@chromium.org722555b2013-10-05 01:16:30 +00001013 dst[SkMatrix::kMPersp0] = SkMScalarToScalar(fMat[0][3]);
1014 dst[SkMatrix::kMPersp1] = SkMScalarToScalar(fMat[1][3]);
1015 dst[SkMatrix::kMPersp2] = SkMScalarToScalar(fMat[3][3]);
1016
reed@google.com8260a892011-06-13 14:02:52 +00001017 return dst;
1018}