blob: 34b532751966008d44cbe9282034c1ed38537dee [file] [log] [blame]
reed@google.com8260a892011-06-13 14:02:52 +00001/*
epoger@google.comec3ed6a2011-07-28 14:26:00 +00002 * Copyright 2011 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
reed@google.com8260a892011-06-13 14:02:52 +00006 */
7
reed@google.com8260a892011-06-13 14:02:52 +00008#include "SkMatrix44.h"
9
reed@google.com7d683352012-12-03 21:19:52 +000010static inline bool eq4(const SkMScalar* SK_RESTRICT a,
11 const SkMScalar* SK_RESTRICT b) {
12 return (a[0] == b[0]) & (a[1] == b[1]) & (a[2] == b[2]) & (a[3] == b[3]);
13}
jamesr@chromium.orgdeb4c162012-11-29 21:17:16 +000014
reed@google.com7d683352012-12-03 21:19:52 +000015bool SkMatrix44::operator==(const SkMatrix44& other) const {
16 if (this == &other) {
17 return true;
18 }
19
20 if (this->isTriviallyIdentity() && other.isTriviallyIdentity()) {
21 return true;
22 }
23
24 const SkMScalar* SK_RESTRICT a = &fMat[0][0];
25 const SkMScalar* SK_RESTRICT b = &other.fMat[0][0];
26
27#if 0
reed@google.com631940c2012-11-27 13:13:22 +000028 for (int i = 0; i < 16; ++i) {
29 if (a[i] != b[i]) {
30 return false;
31 }
32 }
33 return true;
reed@google.com7d683352012-12-03 21:19:52 +000034#else
35 // to reduce branch instructions, we compare 4 at a time.
36 // see bench/Matrix44Bench.cpp for test.
37 if (!eq4(&a[0], &b[0])) {
38 return false;
39 }
40 if (!eq4(&a[4], &b[4])) {
41 return false;
42 }
43 if (!eq4(&a[8], &b[8])) {
44 return false;
45 }
46 return eq4(&a[12], &b[12]);
47#endif
48}
49
50///////////////////////////////////////////////////////////////////////////////
51
52int SkMatrix44::computeTypeMask() const {
53 unsigned mask = 0;
skia.committer@gmail.com0264fb42012-12-06 02:01:25 +000054
reed@google.com7d683352012-12-03 21:19:52 +000055 if (0 != perspX() || 0 != perspY() || 0 != perspZ() || 1 != fMat[3][3]) {
56 return kTranslate_Mask | kScale_Mask | kAffine_Mask | kPerspective_Mask;
57 }
58
59 if (0 != transX() || 0 != transY() || 0 != transZ()) {
60 mask |= kTranslate_Mask;
61 }
62
63 if (1 != scaleX() || 1 != scaleY() || 1 != scaleZ()) {
64 mask |= kScale_Mask;
65 }
66
67 if (0 != fMat[1][0] || 0 != fMat[0][1] || 0 != fMat[0][2] ||
68 0 != fMat[2][0] || 0 != fMat[1][2] || 0 != fMat[2][1]) {
69 mask |= kAffine_Mask;
70 }
71
72 return mask;
reed@google.com8260a892011-06-13 14:02:52 +000073}
74
75///////////////////////////////////////////////////////////////////////////////
76
reed@google.comda9fac02011-06-13 14:46:52 +000077void SkMatrix44::asColMajorf(float dst[]) const {
78 const SkMScalar* src = &fMat[0][0];
79#ifdef SK_MSCALAR_IS_DOUBLE
80 for (int i = 0; i < 16; ++i) {
81 dst[i] = SkMScalarToFloat(src[i]);
82 }
vollick@chromium.org5596a692012-11-13 20:12:00 +000083#elif defined SK_MSCALAR_IS_FLOAT
reed@google.comda9fac02011-06-13 14:46:52 +000084 memcpy(dst, src, 16 * sizeof(float));
85#endif
86}
87
88void SkMatrix44::asColMajord(double dst[]) const {
89 const SkMScalar* src = &fMat[0][0];
90#ifdef SK_MSCALAR_IS_DOUBLE
91 memcpy(dst, src, 16 * sizeof(double));
vollick@chromium.org5596a692012-11-13 20:12:00 +000092#elif defined SK_MSCALAR_IS_FLOAT
reed@google.comda9fac02011-06-13 14:46:52 +000093 for (int i = 0; i < 16; ++i) {
94 dst[i] = SkMScalarToDouble(src[i]);
95 }
96#endif
97}
98
99void SkMatrix44::asRowMajorf(float dst[]) const {
100 const SkMScalar* src = &fMat[0][0];
101 for (int i = 0; i < 4; ++i) {
102 dst[0] = SkMScalarToFloat(src[0]);
103 dst[4] = SkMScalarToFloat(src[1]);
104 dst[8] = SkMScalarToFloat(src[2]);
105 dst[12] = SkMScalarToFloat(src[3]);
106 src += 4;
107 dst += 1;
108 }
109}
110
111void SkMatrix44::asRowMajord(double dst[]) const {
112 const SkMScalar* src = &fMat[0][0];
113 for (int i = 0; i < 4; ++i) {
114 dst[0] = SkMScalarToDouble(src[0]);
115 dst[4] = SkMScalarToDouble(src[1]);
116 dst[8] = SkMScalarToDouble(src[2]);
117 dst[12] = SkMScalarToDouble(src[3]);
118 src += 4;
119 dst += 1;
120 }
121}
122
vollick@chromium.orgf11cf9f2012-11-19 21:02:06 +0000123void SkMatrix44::setColMajorf(const float src[]) {
124 SkMScalar* dst = &fMat[0][0];
125#ifdef SK_MSCALAR_IS_DOUBLE
126 for (int i = 0; i < 16; ++i) {
127 dst[i] = SkMScalarToFloat(src[i]);
128 }
129#elif defined SK_MSCALAR_IS_FLOAT
130 memcpy(dst, src, 16 * sizeof(float));
131#endif
reed@google.com7d683352012-12-03 21:19:52 +0000132
133 this->dirtyTypeMask();
vollick@chromium.orgf11cf9f2012-11-19 21:02:06 +0000134}
135
136void SkMatrix44::setColMajord(const double src[]) {
137 SkMScalar* dst = &fMat[0][0];
138#ifdef SK_MSCALAR_IS_DOUBLE
139 memcpy(dst, src, 16 * sizeof(double));
140#elif defined SK_MSCALAR_IS_FLOAT
141 for (int i = 0; i < 16; ++i) {
robertphillips@google.com93f03322012-12-03 17:35:19 +0000142 dst[i] = SkDoubleToMScalar(src[i]);
vollick@chromium.orgf11cf9f2012-11-19 21:02:06 +0000143 }
144#endif
reed@google.com7d683352012-12-03 21:19:52 +0000145
146 this->dirtyTypeMask();
vollick@chromium.orgf11cf9f2012-11-19 21:02:06 +0000147}
148
149void SkMatrix44::setRowMajorf(const float src[]) {
150 SkMScalar* dst = &fMat[0][0];
151 for (int i = 0; i < 4; ++i) {
152 dst[0] = SkMScalarToFloat(src[0]);
153 dst[4] = SkMScalarToFloat(src[1]);
154 dst[8] = SkMScalarToFloat(src[2]);
155 dst[12] = SkMScalarToFloat(src[3]);
156 src += 4;
157 dst += 1;
158 }
reed@google.com7d683352012-12-03 21:19:52 +0000159 this->dirtyTypeMask();
vollick@chromium.orgf11cf9f2012-11-19 21:02:06 +0000160}
161
162void SkMatrix44::setRowMajord(const double src[]) {
163 SkMScalar* dst = &fMat[0][0];
164 for (int i = 0; i < 4; ++i) {
robertphillips@google.com93f03322012-12-03 17:35:19 +0000165 dst[0] = SkDoubleToMScalar(src[0]);
166 dst[4] = SkDoubleToMScalar(src[1]);
167 dst[8] = SkDoubleToMScalar(src[2]);
168 dst[12] = SkDoubleToMScalar(src[3]);
vollick@chromium.orgf11cf9f2012-11-19 21:02:06 +0000169 src += 4;
170 dst += 1;
171 }
reed@google.com7d683352012-12-03 21:19:52 +0000172 this->dirtyTypeMask();
vollick@chromium.orgf11cf9f2012-11-19 21:02:06 +0000173}
174
reed@google.comda9fac02011-06-13 14:46:52 +0000175///////////////////////////////////////////////////////////////////////////////
176
reed@google.com7d683352012-12-03 21:19:52 +0000177const SkMatrix44& SkMatrix44::I() {
reed@google.com1adad342012-12-10 21:21:27 +0000178 static const SkMatrix44 gIdentity44(kIdentity_Constructor);
179 return gIdentity44;
reed@google.com8260a892011-06-13 14:02:52 +0000180}
181
reed@google.com8260a892011-06-13 14:02:52 +0000182void SkMatrix44::setIdentity() {
shawnsingh@chromium.org5a6cd352013-08-28 18:55:25 +0000183 fMat[0][0] = 1;
184 fMat[0][1] = 0;
185 fMat[0][2] = 0;
186 fMat[0][3] = 0;
187 fMat[1][0] = 0;
188 fMat[1][1] = 1;
189 fMat[1][2] = 0;
190 fMat[1][3] = 0;
191 fMat[2][0] = 0;
192 fMat[2][1] = 0;
193 fMat[2][2] = 1;
194 fMat[2][3] = 0;
195 fMat[3][0] = 0;
196 fMat[3][1] = 0;
197 fMat[3][2] = 0;
198 fMat[3][3] = 1;
reed@google.com7d683352012-12-03 21:19:52 +0000199 this->setTypeMask(kIdentity_Mask);
reed@google.com8260a892011-06-13 14:02:52 +0000200}
201
202void SkMatrix44::set3x3(SkMScalar m00, SkMScalar m01, SkMScalar m02,
203 SkMScalar m10, SkMScalar m11, SkMScalar m12,
204 SkMScalar m20, SkMScalar m21, SkMScalar m22) {
reed@google.com8260a892011-06-13 14:02:52 +0000205 fMat[0][0] = m00; fMat[0][1] = m01; fMat[0][2] = m02; fMat[0][3] = 0;
206 fMat[1][0] = m10; fMat[1][1] = m11; fMat[1][2] = m12; fMat[1][3] = 0;
207 fMat[2][0] = m20; fMat[2][1] = m21; fMat[2][2] = m22; fMat[2][3] = 0;
208 fMat[3][0] = 0; fMat[3][1] = 0; fMat[3][2] = 0; fMat[3][3] = 1;
reed@google.com7d683352012-12-03 21:19:52 +0000209 this->dirtyTypeMask();
reed@google.com8260a892011-06-13 14:02:52 +0000210}
211
reed50d3b572016-05-03 12:13:21 -0700212void SkMatrix44::set3x3ColMajorf(const float src[]) {
213 fMat[0][0] = src[0]; fMat[0][1] = src[3]; fMat[0][2] = src[6]; fMat[0][3] = 0;
214 fMat[1][0] = src[1]; fMat[1][1] = src[4]; fMat[1][2] = src[7]; fMat[1][3] = 0;
215 fMat[2][0] = src[2]; fMat[2][1] = src[5]; fMat[2][2] = src[8]; fMat[2][3] = 0;
216 fMat[3][0] = 0; fMat[3][1] = 0; fMat[3][2] = 0; fMat[3][3] = 1;
217 this->dirtyTypeMask();
218}
219
reed@google.com8260a892011-06-13 14:02:52 +0000220///////////////////////////////////////////////////////////////////////////////
221
reed@google.com99b5c7f2012-12-05 22:13:59 +0000222void SkMatrix44::setTranslate(SkMScalar dx, SkMScalar dy, SkMScalar dz) {
reed@google.com8260a892011-06-13 14:02:52 +0000223 this->setIdentity();
skia.committer@gmail.come659c2e2012-12-04 02:01:25 +0000224
reed@google.com99b5c7f2012-12-05 22:13:59 +0000225 if (!dx && !dy && !dz) {
226 return;
reed@google.com7d683352012-12-03 21:19:52 +0000227 }
skia.committer@gmail.com0264fb42012-12-06 02:01:25 +0000228
reed@google.com99b5c7f2012-12-05 22:13:59 +0000229 fMat[3][0] = dx;
230 fMat[3][1] = dy;
231 fMat[3][2] = dz;
232 this->setTypeMask(kTranslate_Mask);
reed@google.com8260a892011-06-13 14:02:52 +0000233}
234
235void SkMatrix44::preTranslate(SkMScalar dx, SkMScalar dy, SkMScalar dz) {
reed@google.com99b5c7f2012-12-05 22:13:59 +0000236 if (!dx && !dy && !dz) {
237 return;
238 }
239
reed@google.com99b5c7f2012-12-05 22:13:59 +0000240 for (int i = 0; i < 4; ++i) {
commit-bot@chromium.org658e28b2013-10-29 21:08:51 +0000241 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 +0000242 }
243 this->dirtyTypeMask();
reed@google.com8260a892011-06-13 14:02:52 +0000244}
245
246void SkMatrix44::postTranslate(SkMScalar dx, SkMScalar dy, SkMScalar dz) {
reed@google.com99b5c7f2012-12-05 22:13:59 +0000247 if (!dx && !dy && !dz) {
248 return;
249 }
250
251 if (this->getType() & kPerspective_Mask) {
252 for (int i = 0; i < 4; ++i) {
253 fMat[i][0] += fMat[i][3] * dx;
254 fMat[i][1] += fMat[i][3] * dy;
255 fMat[i][2] += fMat[i][3] * dz;
256 }
257 } else {
258 fMat[3][0] += dx;
259 fMat[3][1] += dy;
260 fMat[3][2] += dz;
261 this->dirtyTypeMask();
262 }
reed@google.com8260a892011-06-13 14:02:52 +0000263}
264
265///////////////////////////////////////////////////////////////////////////////
266
267void SkMatrix44::setScale(SkMScalar sx, SkMScalar sy, SkMScalar sz) {
reed@google.com99b5c7f2012-12-05 22:13:59 +0000268 this->setIdentity();
269
270 if (1 == sx && 1 == sy && 1 == sz) {
271 return;
272 }
273
reed@google.com8260a892011-06-13 14:02:52 +0000274 fMat[0][0] = sx;
275 fMat[1][1] = sy;
276 fMat[2][2] = sz;
reed@google.com99b5c7f2012-12-05 22:13:59 +0000277 this->setTypeMask(kScale_Mask);
reed@google.com8260a892011-06-13 14:02:52 +0000278}
279
280void SkMatrix44::preScale(SkMScalar sx, SkMScalar sy, SkMScalar sz) {
reed@google.com99b5c7f2012-12-05 22:13:59 +0000281 if (1 == sx && 1 == sy && 1 == sz) {
282 return;
283 }
skia.committer@gmail.com0264fb42012-12-06 02:01:25 +0000284
shawnsingh@chromium.orgf81f97e2012-12-13 22:21:36 +0000285 // The implementation matrix * pureScale can be shortcut
286 // by knowing that pureScale components effectively scale
287 // the columns of the original matrix.
288 for (int i = 0; i < 4; i++) {
289 fMat[0][i] *= sx;
290 fMat[1][i] *= sy;
291 fMat[2][i] *= sz;
292 }
293 this->dirtyTypeMask();
reed@google.com8260a892011-06-13 14:02:52 +0000294}
295
296void SkMatrix44::postScale(SkMScalar sx, SkMScalar sy, SkMScalar sz) {
reed@google.com99b5c7f2012-12-05 22:13:59 +0000297 if (1 == sx && 1 == sy && 1 == sz) {
298 return;
299 }
skia.committer@gmail.com0264fb42012-12-06 02:01:25 +0000300
reed@google.com8260a892011-06-13 14:02:52 +0000301 for (int i = 0; i < 4; i++) {
302 fMat[i][0] *= sx;
303 fMat[i][1] *= sy;
304 fMat[i][2] *= sz;
305 }
reed@google.com7d683352012-12-03 21:19:52 +0000306 this->dirtyTypeMask();
reed@google.com8260a892011-06-13 14:02:52 +0000307}
308
309///////////////////////////////////////////////////////////////////////////////
310
311void SkMatrix44::setRotateAbout(SkMScalar x, SkMScalar y, SkMScalar z,
312 SkMScalar radians) {
reed@google.com7d683352012-12-03 21:19:52 +0000313 double len2 = (double)x * x + (double)y * y + (double)z * z;
314 if (1 != len2) {
315 if (0 == len2) {
reed@google.com8260a892011-06-13 14:02:52 +0000316 this->setIdentity();
317 return;
318 }
319 double scale = 1 / sqrt(len2);
bsalomon@google.com9d12f5c2011-09-29 18:08:18 +0000320 x = SkDoubleToMScalar(x * scale);
321 y = SkDoubleToMScalar(y * scale);
322 z = SkDoubleToMScalar(z * scale);
reed@google.com8260a892011-06-13 14:02:52 +0000323 }
324 this->setRotateAboutUnit(x, y, z, radians);
325}
326
327void SkMatrix44::setRotateAboutUnit(SkMScalar x, SkMScalar y, SkMScalar z,
328 SkMScalar radians) {
329 double c = cos(radians);
330 double s = sin(radians);
331 double C = 1 - c;
332 double xs = x * s;
333 double ys = y * s;
334 double zs = z * s;
335 double xC = x * C;
336 double yC = y * C;
337 double zC = z * C;
338 double xyC = x * yC;
339 double yzC = y * zC;
340 double zxC = z * xC;
341
342 // if you're looking at wikipedia, remember that we're column major.
bsalomon@google.com9d12f5c2011-09-29 18:08:18 +0000343 this->set3x3(SkDoubleToMScalar(x * xC + c), // scale x
344 SkDoubleToMScalar(xyC + zs), // skew x
345 SkDoubleToMScalar(zxC - ys), // trans x
346
347 SkDoubleToMScalar(xyC - zs), // skew y
348 SkDoubleToMScalar(y * yC + c), // scale y
349 SkDoubleToMScalar(yzC + xs), // trans y
350
351 SkDoubleToMScalar(zxC + ys), // persp x
352 SkDoubleToMScalar(yzC - xs), // persp y
353 SkDoubleToMScalar(z * zC + c)); // persp 2
reed@google.com8260a892011-06-13 14:02:52 +0000354}
355
356///////////////////////////////////////////////////////////////////////////////
357
reed@google.com99b5c7f2012-12-05 22:13:59 +0000358static bool bits_isonly(int value, int mask) {
359 return 0 == (value & ~mask);
360}
361
reed@google.com8260a892011-06-13 14:02:52 +0000362void SkMatrix44::setConcat(const SkMatrix44& a, const SkMatrix44& b) {
reed@google.com99b5c7f2012-12-05 22:13:59 +0000363 const SkMatrix44::TypeMask a_mask = a.getType();
364 const SkMatrix44::TypeMask b_mask = b.getType();
365
366 if (kIdentity_Mask == a_mask) {
reed@google.com7d683352012-12-03 21:19:52 +0000367 *this = b;
368 return;
369 }
reed@google.com99b5c7f2012-12-05 22:13:59 +0000370 if (kIdentity_Mask == b_mask) {
reed@google.com7d683352012-12-03 21:19:52 +0000371 *this = a;
372 return;
373 }
374
375 bool useStorage = (this == &a || this == &b);
376 SkMScalar storage[16];
377 SkMScalar* result = useStorage ? storage : &fMat[0][0];
378
reed@google.com2b165702013-01-17 16:01:19 +0000379 // Both matrices are at most scale+translate
reed@google.com99b5c7f2012-12-05 22:13:59 +0000380 if (bits_isonly(a_mask | b_mask, kScale_Mask | kTranslate_Mask)) {
reed@google.com99b5c7f2012-12-05 22:13:59 +0000381 result[0] = a.fMat[0][0] * b.fMat[0][0];
reed@google.com2b165702013-01-17 16:01:19 +0000382 result[1] = result[2] = result[3] = result[4] = 0;
reed@google.com99b5c7f2012-12-05 22:13:59 +0000383 result[5] = a.fMat[1][1] * b.fMat[1][1];
reed@google.com2b165702013-01-17 16:01:19 +0000384 result[6] = result[7] = result[8] = result[9] = 0;
reed@google.com99b5c7f2012-12-05 22:13:59 +0000385 result[10] = a.fMat[2][2] * b.fMat[2][2];
reed@google.com2b165702013-01-17 16:01:19 +0000386 result[11] = 0;
reed@google.com99b5c7f2012-12-05 22:13:59 +0000387 result[12] = a.fMat[0][0] * b.fMat[3][0] + a.fMat[3][0];
388 result[13] = a.fMat[1][1] * b.fMat[3][1] + a.fMat[3][1];
389 result[14] = a.fMat[2][2] * b.fMat[3][2] + a.fMat[3][2];
390 result[15] = 1;
391 } else {
392 for (int j = 0; j < 4; j++) {
393 for (int i = 0; i < 4; i++) {
commit-bot@chromium.orgbde4ba22014-01-24 18:48:00 +0000394 double value = 0;
reed@google.com99b5c7f2012-12-05 22:13:59 +0000395 for (int k = 0; k < 4; k++) {
commit-bot@chromium.orgbde4ba22014-01-24 18:48:00 +0000396 value += SkMScalarToDouble(a.fMat[k][i]) * b.fMat[j][k];
reed@google.com99b5c7f2012-12-05 22:13:59 +0000397 }
commit-bot@chromium.orgbde4ba22014-01-24 18:48:00 +0000398 *result++ = SkDoubleToMScalar(value);
reed@google.com8260a892011-06-13 14:02:52 +0000399 }
reed@google.com8260a892011-06-13 14:02:52 +0000400 }
401 }
reed@google.com99b5c7f2012-12-05 22:13:59 +0000402
reed@google.com7d683352012-12-03 21:19:52 +0000403 if (useStorage) {
tomhudson@google.com7cfb9c72013-01-17 13:29:35 +0000404 memcpy(fMat, storage, sizeof(storage));
reed@google.com7d683352012-12-03 21:19:52 +0000405 }
reed@google.com7d683352012-12-03 21:19:52 +0000406 this->dirtyTypeMask();
reed@google.com8260a892011-06-13 14:02:52 +0000407}
408
409///////////////////////////////////////////////////////////////////////////////
410
reed@google.com8260a892011-06-13 14:02:52 +0000411/** We always perform the calculation in doubles, to avoid prematurely losing
412 precision along the way. This relies on the compiler automatically
413 promoting our SkMScalar values to double (if needed).
414 */
415double SkMatrix44::determinant() const {
mike@reedtribe.orgf8b1ebc2012-12-10 03:27:47 +0000416 if (this->isIdentity()) {
417 return 1;
418 }
419 if (this->isScaleTranslate()) {
420 return fMat[0][0] * fMat[1][1] * fMat[2][2] * fMat[3][3];
421 }
422
tomhudson@google.com9973a8a2012-12-13 09:55:42 +0000423 double a00 = fMat[0][0];
424 double a01 = fMat[0][1];
425 double a02 = fMat[0][2];
426 double a03 = fMat[0][3];
427 double a10 = fMat[1][0];
428 double a11 = fMat[1][1];
429 double a12 = fMat[1][2];
430 double a13 = fMat[1][3];
431 double a20 = fMat[2][0];
432 double a21 = fMat[2][1];
433 double a22 = fMat[2][2];
434 double a23 = fMat[2][3];
435 double a30 = fMat[3][0];
436 double a31 = fMat[3][1];
437 double a32 = fMat[3][2];
438 double a33 = fMat[3][3];
439
440 double b00 = a00 * a11 - a01 * a10;
441 double b01 = a00 * a12 - a02 * a10;
442 double b02 = a00 * a13 - a03 * a10;
443 double b03 = a01 * a12 - a02 * a11;
444 double b04 = a01 * a13 - a03 * a11;
445 double b05 = a02 * a13 - a03 * a12;
446 double b06 = a20 * a31 - a21 * a30;
447 double b07 = a20 * a32 - a22 * a30;
448 double b08 = a20 * a33 - a23 * a30;
449 double b09 = a21 * a32 - a22 * a31;
450 double b10 = a21 * a33 - a23 * a31;
451 double b11 = a22 * a33 - a23 * a32;
452
453 // Calculate the determinant
454 return b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
reed@google.com8260a892011-06-13 14:02:52 +0000455}
456
457///////////////////////////////////////////////////////////////////////////////
458
vmpstra8d45592015-06-30 13:36:04 -0700459static bool is_matrix_finite(const SkMatrix44& matrix) {
460 SkMScalar accumulator = 0;
461 for (int row = 0; row < 4; ++row) {
462 for (int col = 0; col < 4; ++col) {
463 accumulator *= matrix.get(row, col);
464 }
465 }
466 return accumulator == 0;
467}
468
469bool SkMatrix44::invert(SkMatrix44* storage) const {
mike@reedtribe.orgf8b1ebc2012-12-10 03:27:47 +0000470 if (this->isIdentity()) {
vmpstra8d45592015-06-30 13:36:04 -0700471 if (storage) {
472 storage->setIdentity();
reed@google.com7d683352012-12-03 21:19:52 +0000473 }
commit-bot@chromium.org178acd22013-11-20 21:32:27 +0000474 return true;
reed@google.com7d683352012-12-03 21:19:52 +0000475 }
commit-bot@chromium.org178acd22013-11-20 21:32:27 +0000476
mike@reedtribe.orgf8b1ebc2012-12-10 03:27:47 +0000477 if (this->isTranslate()) {
vmpstra8d45592015-06-30 13:36:04 -0700478 if (storage) {
479 storage->setTranslate(-fMat[3][0], -fMat[3][1], -fMat[3][2]);
reed@google.com99b5c7f2012-12-05 22:13:59 +0000480 }
481 return true;
482 }
commit-bot@chromium.org178acd22013-11-20 21:32:27 +0000483
vmpstra8d45592015-06-30 13:36:04 -0700484 SkMatrix44 tmp(kUninitialized_Constructor);
485 // Use storage if it's available and distinct from this matrix.
486 SkMatrix44* inverse = (storage && storage != this) ? storage : &tmp;
mike@reedtribe.orgf8b1ebc2012-12-10 03:27:47 +0000487 if (this->isScaleTranslate()) {
reed@google.com99b5c7f2012-12-05 22:13:59 +0000488 if (0 == fMat[0][0] * fMat[1][1] * fMat[2][2]) {
489 return false;
490 }
reed@google.com99b5c7f2012-12-05 22:13:59 +0000491
vmpstra8d45592015-06-30 13:36:04 -0700492 double invXScale = 1 / fMat[0][0];
493 double invYScale = 1 / fMat[1][1];
494 double invZScale = 1 / fMat[2][2];
reed@google.com99b5c7f2012-12-05 22:13:59 +0000495
vmpstra8d45592015-06-30 13:36:04 -0700496 inverse->fMat[0][0] = SkDoubleToMScalar(invXScale);
497 inverse->fMat[0][1] = 0;
498 inverse->fMat[0][2] = 0;
499 inverse->fMat[0][3] = 0;
skia.committer@gmail.com772c4e62013-08-30 07:01:34 +0000500
vmpstra8d45592015-06-30 13:36:04 -0700501 inverse->fMat[1][0] = 0;
502 inverse->fMat[1][1] = SkDoubleToMScalar(invYScale);
503 inverse->fMat[1][2] = 0;
504 inverse->fMat[1][3] = 0;
skia.committer@gmail.com772c4e62013-08-30 07:01:34 +0000505
vmpstra8d45592015-06-30 13:36:04 -0700506 inverse->fMat[2][0] = 0;
507 inverse->fMat[2][1] = 0;
508 inverse->fMat[2][2] = SkDoubleToMScalar(invZScale);
509 inverse->fMat[2][3] = 0;
skia.committer@gmail.com772c4e62013-08-30 07:01:34 +0000510
vmpstra8d45592015-06-30 13:36:04 -0700511 inverse->fMat[3][0] = SkDoubleToMScalar(-fMat[3][0] * invXScale);
512 inverse->fMat[3][1] = SkDoubleToMScalar(-fMat[3][1] * invYScale);
513 inverse->fMat[3][2] = SkDoubleToMScalar(-fMat[3][2] * invZScale);
514 inverse->fMat[3][3] = 1;
shawnsingh@chromium.orgb6823c12013-08-22 20:24:21 +0000515
vmpstra8d45592015-06-30 13:36:04 -0700516 inverse->setTypeMask(this->getType());
517
518 if (!is_matrix_finite(*inverse)) {
519 return false;
shawnsingh@chromium.org5a6cd352013-08-28 18:55:25 +0000520 }
vmpstra8d45592015-06-30 13:36:04 -0700521 if (storage && inverse != storage) {
522 *storage = *inverse;
523 }
reed@google.com99b5c7f2012-12-05 22:13:59 +0000524 return true;
525 }
526
tomhudson@google.com9973a8a2012-12-13 09:55:42 +0000527 double a00 = fMat[0][0];
528 double a01 = fMat[0][1];
529 double a02 = fMat[0][2];
530 double a03 = fMat[0][3];
531 double a10 = fMat[1][0];
532 double a11 = fMat[1][1];
533 double a12 = fMat[1][2];
534 double a13 = fMat[1][3];
535 double a20 = fMat[2][0];
536 double a21 = fMat[2][1];
537 double a22 = fMat[2][2];
538 double a23 = fMat[2][3];
539 double a30 = fMat[3][0];
540 double a31 = fMat[3][1];
541 double a32 = fMat[3][2];
542 double a33 = fMat[3][3];
543
shawnsingh@chromium.orgb6823c12013-08-22 20:24:21 +0000544 if (!(this->getType() & kPerspective_Mask)) {
545 // If we know the matrix has no perspective, then the perspective
546 // component is (0, 0, 0, 1). We can use this information to save a lot
547 // of arithmetic that would otherwise be spent to compute the inverse
548 // of a general matrix.
549
550 SkASSERT(a03 == 0);
551 SkASSERT(a13 == 0);
552 SkASSERT(a23 == 0);
553 SkASSERT(a33 == 1);
554
555 double b00 = a00 * a11 - a01 * a10;
556 double b01 = a00 * a12 - a02 * a10;
557 double b03 = a01 * a12 - a02 * a11;
558 double b06 = a20 * a31 - a21 * a30;
559 double b07 = a20 * a32 - a22 * a30;
560 double b08 = a20;
561 double b09 = a21 * a32 - a22 * a31;
562 double b10 = a21;
563 double b11 = a22;
564
565 // Calculate the determinant
566 double det = b00 * b11 - b01 * b10 + b03 * b08;
567
568 double invdet = 1.0 / det;
569 // If det is zero, we want to return false. However, we also want to return false
570 // if 1/det overflows to infinity (i.e. det is denormalized). Both of these are
571 // handled by checking that 1/det is finite.
572 if (!sk_float_isfinite(invdet)) {
573 return false;
574 }
shawnsingh@chromium.orgb6823c12013-08-22 20:24:21 +0000575
576 b00 *= invdet;
577 b01 *= invdet;
578 b03 *= invdet;
579 b06 *= invdet;
580 b07 *= invdet;
581 b08 *= invdet;
582 b09 *= invdet;
583 b10 *= invdet;
584 b11 *= invdet;
585
586 inverse->fMat[0][0] = SkDoubleToMScalar(a11 * b11 - a12 * b10);
587 inverse->fMat[0][1] = SkDoubleToMScalar(a02 * b10 - a01 * b11);
588 inverse->fMat[0][2] = SkDoubleToMScalar(b03);
589 inverse->fMat[0][3] = 0;
590 inverse->fMat[1][0] = SkDoubleToMScalar(a12 * b08 - a10 * b11);
591 inverse->fMat[1][1] = SkDoubleToMScalar(a00 * b11 - a02 * b08);
592 inverse->fMat[1][2] = SkDoubleToMScalar(-b01);
593 inverse->fMat[1][3] = 0;
594 inverse->fMat[2][0] = SkDoubleToMScalar(a10 * b10 - a11 * b08);
595 inverse->fMat[2][1] = SkDoubleToMScalar(a01 * b08 - a00 * b10);
596 inverse->fMat[2][2] = SkDoubleToMScalar(b00);
597 inverse->fMat[2][3] = 0;
598 inverse->fMat[3][0] = SkDoubleToMScalar(a11 * b07 - a10 * b09 - a12 * b06);
599 inverse->fMat[3][1] = SkDoubleToMScalar(a00 * b09 - a01 * b07 + a02 * b06);
600 inverse->fMat[3][2] = SkDoubleToMScalar(a31 * b01 - a30 * b03 - a32 * b00);
601 inverse->fMat[3][3] = 1;
602
603 inverse->setTypeMask(this->getType());
vmpstra8d45592015-06-30 13:36:04 -0700604 if (!is_matrix_finite(*inverse)) {
605 return false;
606 }
607 if (storage && inverse != storage) {
608 *storage = *inverse;
609 }
shawnsingh@chromium.orgb6823c12013-08-22 20:24:21 +0000610 return true;
611 }
612
tomhudson@google.com9973a8a2012-12-13 09:55:42 +0000613 double b00 = a00 * a11 - a01 * a10;
614 double b01 = a00 * a12 - a02 * a10;
615 double b02 = a00 * a13 - a03 * a10;
616 double b03 = a01 * a12 - a02 * a11;
617 double b04 = a01 * a13 - a03 * a11;
618 double b05 = a02 * a13 - a03 * a12;
619 double b06 = a20 * a31 - a21 * a30;
620 double b07 = a20 * a32 - a22 * a30;
621 double b08 = a20 * a33 - a23 * a30;
622 double b09 = a21 * a32 - a22 * a31;
623 double b10 = a21 * a33 - a23 * a31;
624 double b11 = a22 * a33 - a23 * a32;
625
626 // Calculate the determinant
627 double det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
628
commit-bot@chromium.orgf02f0782013-08-20 15:25:04 +0000629 double invdet = 1.0 / det;
630 // If det is zero, we want to return false. However, we also want to return false
631 // if 1/det overflows to infinity (i.e. det is denormalized). Both of these are
632 // handled by checking that 1/det is finite.
633 if (!sk_float_isfinite(invdet)) {
reed@google.com8260a892011-06-13 14:02:52 +0000634 return false;
635 }
reed@google.com8260a892011-06-13 14:02:52 +0000636
tomhudson@google.com9973a8a2012-12-13 09:55:42 +0000637 b00 *= invdet;
638 b01 *= invdet;
639 b02 *= invdet;
640 b03 *= invdet;
641 b04 *= invdet;
642 b05 *= invdet;
643 b06 *= invdet;
644 b07 *= invdet;
645 b08 *= invdet;
646 b09 *= invdet;
647 b10 *= invdet;
648 b11 *= invdet;
reed@google.com8260a892011-06-13 14:02:52 +0000649
tomhudson@google.com9973a8a2012-12-13 09:55:42 +0000650 inverse->fMat[0][0] = SkDoubleToMScalar(a11 * b11 - a12 * b10 + a13 * b09);
651 inverse->fMat[0][1] = SkDoubleToMScalar(a02 * b10 - a01 * b11 - a03 * b09);
652 inverse->fMat[0][2] = SkDoubleToMScalar(a31 * b05 - a32 * b04 + a33 * b03);
653 inverse->fMat[0][3] = SkDoubleToMScalar(a22 * b04 - a21 * b05 - a23 * b03);
654 inverse->fMat[1][0] = SkDoubleToMScalar(a12 * b08 - a10 * b11 - a13 * b07);
655 inverse->fMat[1][1] = SkDoubleToMScalar(a00 * b11 - a02 * b08 + a03 * b07);
656 inverse->fMat[1][2] = SkDoubleToMScalar(a32 * b02 - a30 * b05 - a33 * b01);
657 inverse->fMat[1][3] = SkDoubleToMScalar(a20 * b05 - a22 * b02 + a23 * b01);
658 inverse->fMat[2][0] = SkDoubleToMScalar(a10 * b10 - a11 * b08 + a13 * b06);
659 inverse->fMat[2][1] = SkDoubleToMScalar(a01 * b08 - a00 * b10 - a03 * b06);
660 inverse->fMat[2][2] = SkDoubleToMScalar(a30 * b04 - a31 * b02 + a33 * b00);
661 inverse->fMat[2][3] = SkDoubleToMScalar(a21 * b02 - a20 * b04 - a23 * b00);
662 inverse->fMat[3][0] = SkDoubleToMScalar(a11 * b07 - a10 * b09 - a12 * b06);
663 inverse->fMat[3][1] = SkDoubleToMScalar(a00 * b09 - a01 * b07 + a02 * b06);
664 inverse->fMat[3][2] = SkDoubleToMScalar(a31 * b01 - a30 * b03 - a32 * b00);
665 inverse->fMat[3][3] = SkDoubleToMScalar(a20 * b03 - a21 * b01 + a22 * b00);
666 inverse->dirtyTypeMask();
reed@google.com8260a892011-06-13 14:02:52 +0000667
vmpstra8d45592015-06-30 13:36:04 -0700668 inverse->setTypeMask(this->getType());
669 if (!is_matrix_finite(*inverse)) {
670 return false;
671 }
672 if (storage && inverse != storage) {
673 *storage = *inverse;
674 }
reed@google.com8260a892011-06-13 14:02:52 +0000675 return true;
676}
677
678///////////////////////////////////////////////////////////////////////////////
679
vollick@chromium.org9b21c252012-11-14 21:33:55 +0000680void SkMatrix44::transpose() {
681 SkTSwap(fMat[0][1], fMat[1][0]);
682 SkTSwap(fMat[0][2], fMat[2][0]);
683 SkTSwap(fMat[0][3], fMat[3][0]);
684 SkTSwap(fMat[1][2], fMat[2][1]);
685 SkTSwap(fMat[1][3], fMat[3][1]);
686 SkTSwap(fMat[2][3], fMat[3][2]);
reed@google.com7d683352012-12-03 21:19:52 +0000687
688 if (!this->isTriviallyIdentity()) {
689 this->dirtyTypeMask();
690 }
vollick@chromium.org9b21c252012-11-14 21:33:55 +0000691}
692
693///////////////////////////////////////////////////////////////////////////////
694
reed@google.com1ea95be2012-11-09 21:39:48 +0000695void SkMatrix44::mapScalars(const SkScalar src[4], SkScalar dst[4]) const {
reed@google.com7d683352012-12-03 21:19:52 +0000696 SkScalar storage[4];
697 SkScalar* result = (src == dst) ? storage : dst;
698
reed@google.com8260a892011-06-13 14:02:52 +0000699 for (int i = 0; i < 4; i++) {
700 SkMScalar value = 0;
701 for (int j = 0; j < 4; j++) {
702 value += fMat[j][i] * src[j];
703 }
bsalomon@google.com72e49b82011-10-27 21:47:03 +0000704 result[i] = SkMScalarToScalar(value);
reed@google.com8260a892011-06-13 14:02:52 +0000705 }
skia.committer@gmail.com0264fb42012-12-06 02:01:25 +0000706
reed@google.com7d683352012-12-03 21:19:52 +0000707 if (storage == result) {
708 memcpy(dst, storage, sizeof(storage));
709 }
reed@google.com8260a892011-06-13 14:02:52 +0000710}
711
reed@google.com1ea95be2012-11-09 21:39:48 +0000712#ifdef SK_MSCALAR_IS_DOUBLE
reed@google.com7d683352012-12-03 21:19:52 +0000713
reed@google.com1ea95be2012-11-09 21:39:48 +0000714void SkMatrix44::mapMScalars(const SkMScalar src[4], SkMScalar dst[4]) const {
reed@google.com7d683352012-12-03 21:19:52 +0000715 SkMScalar storage[4];
716 SkMScalar* result = (src == dst) ? storage : dst;
skia.committer@gmail.com0264fb42012-12-06 02:01:25 +0000717
reed@google.com1ea95be2012-11-09 21:39:48 +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 }
reed@google.com7d683352012-12-03 21:19:52 +0000723 result[i] = value;
reed@google.com1ea95be2012-11-09 21:39:48 +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.com1ea95be2012-11-09 21:39:48 +0000729}
reed@google.com7d683352012-12-03 21:19:52 +0000730
reed@google.com1ea95be2012-11-09 21:39:48 +0000731#endif
732
reed@google.com99b5c7f2012-12-05 22:13:59 +0000733typedef void (*Map2Procf)(const SkMScalar mat[][4], const float src2[], int count, float dst4[]);
734typedef void (*Map2Procd)(const SkMScalar mat[][4], const double src2[], int count, double dst4[]);
735
736static void map2_if(const SkMScalar mat[][4], const float* SK_RESTRICT src2,
737 int count, float* SK_RESTRICT dst4) {
738 for (int i = 0; i < count; ++i) {
739 dst4[0] = src2[0];
740 dst4[1] = src2[1];
741 dst4[2] = 0;
742 dst4[3] = 1;
743 src2 += 2;
744 dst4 += 4;
745 }
746}
747
748static void map2_id(const SkMScalar mat[][4], const double* SK_RESTRICT src2,
749 int count, double* SK_RESTRICT dst4) {
750 for (int i = 0; i < count; ++i) {
751 dst4[0] = src2[0];
752 dst4[1] = src2[1];
753 dst4[2] = 0;
754 dst4[3] = 1;
755 src2 += 2;
756 dst4 += 4;
757 }
758}
759
760static void map2_tf(const SkMScalar mat[][4], const float* SK_RESTRICT src2,
761 int count, float* SK_RESTRICT dst4) {
762 const float mat30 = SkMScalarToFloat(mat[3][0]);
763 const float mat31 = SkMScalarToFloat(mat[3][1]);
764 const float mat32 = SkMScalarToFloat(mat[3][2]);
765 for (int n = 0; n < count; ++n) {
766 dst4[0] = src2[0] + mat30;
767 dst4[1] = src2[1] + mat31;
768 dst4[2] = mat32;
769 dst4[3] = 1;
770 src2 += 2;
771 dst4 += 4;
772 }
773}
774
775static void map2_td(const SkMScalar mat[][4], const double* SK_RESTRICT src2,
776 int count, double* SK_RESTRICT dst4) {
777 for (int n = 0; n < count; ++n) {
778 dst4[0] = src2[0] + mat[3][0];
779 dst4[1] = src2[1] + mat[3][1];
780 dst4[2] = mat[3][2];
781 dst4[3] = 1;
782 src2 += 2;
783 dst4 += 4;
784 }
785}
786
787static void map2_sf(const SkMScalar mat[][4], const float* SK_RESTRICT src2,
788 int count, float* SK_RESTRICT dst4) {
789 const float mat32 = SkMScalarToFloat(mat[3][2]);
790 for (int n = 0; n < count; ++n) {
791 dst4[0] = SkMScalarToFloat(mat[0][0] * src2[0] + mat[3][0]);
792 dst4[1] = SkMScalarToFloat(mat[1][1] * src2[1] + mat[3][1]);
793 dst4[2] = mat32;
794 dst4[3] = 1;
795 src2 += 2;
796 dst4 += 4;
797 }
798}
799
800static void map2_sd(const SkMScalar mat[][4], const double* SK_RESTRICT src2,
801 int count, double* SK_RESTRICT dst4) {
802 for (int n = 0; n < count; ++n) {
803 dst4[0] = mat[0][0] * src2[0] + mat[3][0];
804 dst4[1] = mat[1][1] * src2[1] + mat[3][1];
805 dst4[2] = mat[3][2];
806 dst4[3] = 1;
807 src2 += 2;
808 dst4 += 4;
809 }
810}
811
812static void map2_af(const SkMScalar mat[][4], const float* SK_RESTRICT src2,
813 int count, float* SK_RESTRICT dst4) {
commit-bot@chromium.org658e28b2013-10-29 21:08:51 +0000814 SkMScalar r;
reed@google.com99b5c7f2012-12-05 22:13:59 +0000815 for (int n = 0; n < count; ++n) {
commit-bot@chromium.org658e28b2013-10-29 21:08:51 +0000816 SkMScalar sx = SkFloatToMScalar(src2[0]);
817 SkMScalar sy = SkFloatToMScalar(src2[1]);
reed@google.com99b5c7f2012-12-05 22:13:59 +0000818 r = mat[0][0] * sx + mat[1][0] * sy + mat[3][0];
819 dst4[0] = SkMScalarToFloat(r);
820 r = mat[0][1] * sx + mat[1][1] * sy + mat[3][1];
821 dst4[1] = SkMScalarToFloat(r);
822 r = mat[0][2] * sx + mat[1][2] * sy + mat[3][2];
823 dst4[2] = SkMScalarToFloat(r);
824 dst4[3] = 1;
825 src2 += 2;
826 dst4 += 4;
827 }
828}
829
830static void map2_ad(const SkMScalar mat[][4], const double* SK_RESTRICT src2,
831 int count, double* SK_RESTRICT dst4) {
832 for (int n = 0; n < count; ++n) {
833 double sx = src2[0];
834 double sy = src2[1];
835 dst4[0] = mat[0][0] * sx + mat[1][0] * sy + mat[3][0];
836 dst4[1] = mat[0][1] * sx + mat[1][1] * sy + mat[3][1];
837 dst4[2] = mat[0][2] * sx + mat[1][2] * sy + mat[3][2];
838 dst4[3] = 1;
839 src2 += 2;
840 dst4 += 4;
841 }
842}
843
844static void map2_pf(const SkMScalar mat[][4], const float* SK_RESTRICT src2,
845 int count, float* SK_RESTRICT dst4) {
commit-bot@chromium.org658e28b2013-10-29 21:08:51 +0000846 SkMScalar r;
reed@google.com99b5c7f2012-12-05 22:13:59 +0000847 for (int n = 0; n < count; ++n) {
commit-bot@chromium.org658e28b2013-10-29 21:08:51 +0000848 SkMScalar sx = SkFloatToMScalar(src2[0]);
849 SkMScalar sy = SkFloatToMScalar(src2[1]);
reed@google.com99b5c7f2012-12-05 22:13:59 +0000850 for (int i = 0; i < 4; i++) {
commit-bot@chromium.org658e28b2013-10-29 21:08:51 +0000851 r = mat[0][i] * sx + mat[1][i] * sy + mat[3][i];
852 dst4[i] = SkMScalarToFloat(r);
reed@google.com99b5c7f2012-12-05 22:13:59 +0000853 }
854 src2 += 2;
855 dst4 += 4;
856 }
857}
858
859static void map2_pd(const SkMScalar mat[][4], const double* SK_RESTRICT src2,
860 int count, double* SK_RESTRICT dst4) {
861 for (int n = 0; n < count; ++n) {
862 double sx = src2[0];
863 double sy = src2[1];
864 for (int i = 0; i < 4; i++) {
865 dst4[i] = mat[0][i] * sx + mat[1][i] * sy + mat[3][i];
866 }
867 src2 += 2;
868 dst4 += 4;
869 }
870}
871
872void SkMatrix44::map2(const float src2[], int count, float dst4[]) const {
873 static const Map2Procf gProc[] = {
874 map2_if, map2_tf, map2_sf, map2_sf, map2_af, map2_af, map2_af, map2_af
875 };
876
877 TypeMask mask = this->getType();
878 Map2Procf proc = (mask & kPerspective_Mask) ? map2_pf : gProc[mask];
879 proc(fMat, src2, count, dst4);
880}
881
882void SkMatrix44::map2(const double src2[], int count, double dst4[]) const {
883 static const Map2Procd gProc[] = {
884 map2_id, map2_td, map2_sd, map2_sd, map2_ad, map2_ad, map2_ad, map2_ad
885 };
skia.committer@gmail.com0264fb42012-12-06 02:01:25 +0000886
reed@google.com99b5c7f2012-12-05 22:13:59 +0000887 TypeMask mask = this->getType();
888 Map2Procd proc = (mask & kPerspective_Mask) ? map2_pd : gProc[mask];
889 proc(fMat, src2, count, dst4);
890}
891
tomhudsonfaccb8e2014-09-26 11:45:48 -0700892bool SkMatrix44::preserves2dAxisAlignment (SkMScalar epsilon) const {
893
894 // Can't check (mask & kPerspective_Mask) because Z isn't relevant here.
895 if (0 != perspX() || 0 != perspY()) return false;
896
897 // A matrix with two non-zeroish values in any of the upper right
898 // rows or columns will skew. If only one value in each row or
899 // column is non-zeroish, we get a scale plus perhaps a 90-degree
900 // rotation.
901 int col0 = 0;
902 int col1 = 0;
903 int row0 = 0;
904 int row1 = 0;
905
906 // Must test against epsilon, not 0, because we can get values
907 // around 6e-17 in the matrix that "should" be 0.
908
909 if (SkMScalarAbs(fMat[0][0]) > epsilon) {
910 col0++;
911 row0++;
912 }
913 if (SkMScalarAbs(fMat[0][1]) > epsilon) {
914 col1++;
915 row0++;
916 }
917 if (SkMScalarAbs(fMat[1][0]) > epsilon) {
918 col0++;
919 row1++;
920 }
921 if (SkMScalarAbs(fMat[1][1]) > epsilon) {
922 col1++;
923 row1++;
924 }
925 if (col0 > 1 || col1 > 1 || row0 > 1 || row1 > 1) {
926 return false;
927 }
928
929 return true;
930}
931
reed@google.com8260a892011-06-13 14:02:52 +0000932///////////////////////////////////////////////////////////////////////////////
933
934void SkMatrix44::dump() const {
tomhudson@google.com9ac4a892011-06-28 13:53:13 +0000935 static const char* format =
936 "[%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 +0000937#if 0
tomhudson@google.com9ac4a892011-06-28 13:53:13 +0000938 SkDebugf(format,
reed@google.com8260a892011-06-13 14:02:52 +0000939 fMat[0][0], fMat[1][0], fMat[2][0], fMat[3][0],
940 fMat[0][1], fMat[1][1], fMat[2][1], fMat[3][1],
941 fMat[0][2], fMat[1][2], fMat[2][2], fMat[3][2],
942 fMat[0][3], fMat[1][3], fMat[2][3], fMat[3][3]);
tomhudson@google.com9ac4a892011-06-28 13:53:13 +0000943#else
944 SkDebugf(format,
945 fMat[0][0], fMat[0][1], fMat[0][2], fMat[0][3],
946 fMat[1][0], fMat[1][1], fMat[1][2], fMat[1][3],
947 fMat[2][0], fMat[2][1], fMat[2][2], fMat[2][3],
948 fMat[3][0], fMat[3][1], fMat[3][2], fMat[3][3]);
reed@google.com8260a892011-06-13 14:02:52 +0000949#endif
950}
951
952///////////////////////////////////////////////////////////////////////////////
953
954static void initFromMatrix(SkMScalar dst[4][4], const SkMatrix& src) {
bsalomon@google.com72e49b82011-10-27 21:47:03 +0000955 dst[0][0] = SkScalarToMScalar(src[SkMatrix::kMScaleX]);
956 dst[1][0] = SkScalarToMScalar(src[SkMatrix::kMSkewX]);
shawnsingh@chromium.org5a6cd352013-08-28 18:55:25 +0000957 dst[2][0] = 0;
bsalomon@google.com72e49b82011-10-27 21:47:03 +0000958 dst[3][0] = SkScalarToMScalar(src[SkMatrix::kMTransX]);
959 dst[0][1] = SkScalarToMScalar(src[SkMatrix::kMSkewY]);
960 dst[1][1] = SkScalarToMScalar(src[SkMatrix::kMScaleY]);
shawnsingh@chromium.org5a6cd352013-08-28 18:55:25 +0000961 dst[2][1] = 0;
bsalomon@google.com72e49b82011-10-27 21:47:03 +0000962 dst[3][1] = SkScalarToMScalar(src[SkMatrix::kMTransY]);
shawnsingh@chromium.org5a6cd352013-08-28 18:55:25 +0000963 dst[0][2] = 0;
964 dst[1][2] = 0;
965 dst[2][2] = 1;
966 dst[3][2] = 0;
commit-bot@chromium.org722555b2013-10-05 01:16:30 +0000967 dst[0][3] = SkScalarToMScalar(src[SkMatrix::kMPersp0]);
968 dst[1][3] = SkScalarToMScalar(src[SkMatrix::kMPersp1]);
shawnsingh@chromium.org5a6cd352013-08-28 18:55:25 +0000969 dst[2][3] = 0;
commit-bot@chromium.org722555b2013-10-05 01:16:30 +0000970 dst[3][3] = SkScalarToMScalar(src[SkMatrix::kMPersp2]);
reed@google.com8260a892011-06-13 14:02:52 +0000971}
972
973SkMatrix44::SkMatrix44(const SkMatrix& src) {
fs88640cf2014-12-16 08:36:11 -0800974 this->operator=(src);
reed@google.com8260a892011-06-13 14:02:52 +0000975}
976
977SkMatrix44& SkMatrix44::operator=(const SkMatrix& src) {
978 initFromMatrix(fMat, src);
reed@google.com7d683352012-12-03 21:19:52 +0000979
980 if (src.isIdentity()) {
981 this->setTypeMask(kIdentity_Mask);
982 } else {
983 this->dirtyTypeMask();
984 }
reed@google.com8260a892011-06-13 14:02:52 +0000985 return *this;
986}
987
988SkMatrix44::operator SkMatrix() const {
989 SkMatrix dst;
reed@google.com8260a892011-06-13 14:02:52 +0000990
bsalomon@google.com72e49b82011-10-27 21:47:03 +0000991 dst[SkMatrix::kMScaleX] = SkMScalarToScalar(fMat[0][0]);
992 dst[SkMatrix::kMSkewX] = SkMScalarToScalar(fMat[1][0]);
993 dst[SkMatrix::kMTransX] = SkMScalarToScalar(fMat[3][0]);
reed@google.com8260a892011-06-13 14:02:52 +0000994
bsalomon@google.com72e49b82011-10-27 21:47:03 +0000995 dst[SkMatrix::kMSkewY] = SkMScalarToScalar(fMat[0][1]);
996 dst[SkMatrix::kMScaleY] = SkMScalarToScalar(fMat[1][1]);
997 dst[SkMatrix::kMTransY] = SkMScalarToScalar(fMat[3][1]);
reed@google.com8260a892011-06-13 14:02:52 +0000998
commit-bot@chromium.org722555b2013-10-05 01:16:30 +0000999 dst[SkMatrix::kMPersp0] = SkMScalarToScalar(fMat[0][3]);
1000 dst[SkMatrix::kMPersp1] = SkMScalarToScalar(fMat[1][3]);
1001 dst[SkMatrix::kMPersp2] = SkMScalarToScalar(fMat[3][3]);
1002
reed@google.com8260a892011-06-13 14:02:52 +00001003 return dst;
1004}