blob: 7982c3088b7054b1679b2070167ba740795847a6 [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001
reed@google.com8260a892011-06-13 14:02:52 +00002/*
epoger@google.comec3ed6a2011-07-28 14:26:00 +00003 * Copyright 2011 Google Inc.
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
reed@google.com8260a892011-06-13 14:02:52 +00007 */
8
9
epoger@google.comec3ed6a2011-07-28 14:26:00 +000010
reed@google.com8260a892011-06-13 14:02:52 +000011#include "SkMatrix44.h"
12
reed@google.com8260a892011-06-13 14:02:52 +000013SkMatrix44::SkMatrix44(const SkMatrix44& src) {
14 memcpy(this, &src, sizeof(src));
15}
16
17SkMatrix44::SkMatrix44(const SkMatrix44& a, const SkMatrix44& b) {
18 this->setConcat(a, b);
19}
20
reed@google.com7d683352012-12-03 21:19:52 +000021static inline bool eq4(const SkMScalar* SK_RESTRICT a,
22 const SkMScalar* SK_RESTRICT b) {
23 return (a[0] == b[0]) & (a[1] == b[1]) & (a[2] == b[2]) & (a[3] == b[3]);
24}
jamesr@chromium.orgdeb4c162012-11-29 21:17:16 +000025
reed@google.com7d683352012-12-03 21:19:52 +000026bool SkMatrix44::operator==(const SkMatrix44& other) const {
27 if (this == &other) {
28 return true;
29 }
30
31 if (this->isTriviallyIdentity() && other.isTriviallyIdentity()) {
32 return true;
33 }
34
35 const SkMScalar* SK_RESTRICT a = &fMat[0][0];
36 const SkMScalar* SK_RESTRICT b = &other.fMat[0][0];
37
38#if 0
reed@google.com631940c2012-11-27 13:13:22 +000039 for (int i = 0; i < 16; ++i) {
40 if (a[i] != b[i]) {
41 return false;
42 }
43 }
44 return true;
reed@google.com7d683352012-12-03 21:19:52 +000045#else
46 // to reduce branch instructions, we compare 4 at a time.
47 // see bench/Matrix44Bench.cpp for test.
48 if (!eq4(&a[0], &b[0])) {
49 return false;
50 }
51 if (!eq4(&a[4], &b[4])) {
52 return false;
53 }
54 if (!eq4(&a[8], &b[8])) {
55 return false;
56 }
57 return eq4(&a[12], &b[12]);
58#endif
59}
60
61///////////////////////////////////////////////////////////////////////////////
62
63int SkMatrix44::computeTypeMask() const {
64 unsigned mask = 0;
skia.committer@gmail.come659c2e2012-12-04 02:01:25 +000065
reed@google.com7d683352012-12-03 21:19:52 +000066 if (0 != perspX() || 0 != perspY() || 0 != perspZ() || 1 != fMat[3][3]) {
67 return kTranslate_Mask | kScale_Mask | kAffine_Mask | kPerspective_Mask;
68 }
69
70 if (0 != transX() || 0 != transY() || 0 != transZ()) {
71 mask |= kTranslate_Mask;
72 }
73
74 if (1 != scaleX() || 1 != scaleY() || 1 != scaleZ()) {
75 mask |= kScale_Mask;
76 }
77
78 if (0 != fMat[1][0] || 0 != fMat[0][1] || 0 != fMat[0][2] ||
79 0 != fMat[2][0] || 0 != fMat[1][2] || 0 != fMat[2][1]) {
80 mask |= kAffine_Mask;
81 }
82
83 return mask;
reed@google.com8260a892011-06-13 14:02:52 +000084}
85
86///////////////////////////////////////////////////////////////////////////////
87
reed@google.comda9fac02011-06-13 14:46:52 +000088void SkMatrix44::asColMajorf(float dst[]) const {
89 const SkMScalar* src = &fMat[0][0];
90#ifdef SK_MSCALAR_IS_DOUBLE
91 for (int i = 0; i < 16; ++i) {
92 dst[i] = SkMScalarToFloat(src[i]);
93 }
vollick@chromium.org5596a692012-11-13 20:12:00 +000094#elif defined SK_MSCALAR_IS_FLOAT
reed@google.comda9fac02011-06-13 14:46:52 +000095 memcpy(dst, src, 16 * sizeof(float));
96#endif
97}
98
99void SkMatrix44::asColMajord(double dst[]) const {
100 const SkMScalar* src = &fMat[0][0];
101#ifdef SK_MSCALAR_IS_DOUBLE
102 memcpy(dst, src, 16 * sizeof(double));
vollick@chromium.org5596a692012-11-13 20:12:00 +0000103#elif defined SK_MSCALAR_IS_FLOAT
reed@google.comda9fac02011-06-13 14:46:52 +0000104 for (int i = 0; i < 16; ++i) {
105 dst[i] = SkMScalarToDouble(src[i]);
106 }
107#endif
108}
109
110void SkMatrix44::asRowMajorf(float dst[]) const {
111 const SkMScalar* src = &fMat[0][0];
112 for (int i = 0; i < 4; ++i) {
113 dst[0] = SkMScalarToFloat(src[0]);
114 dst[4] = SkMScalarToFloat(src[1]);
115 dst[8] = SkMScalarToFloat(src[2]);
116 dst[12] = SkMScalarToFloat(src[3]);
117 src += 4;
118 dst += 1;
119 }
120}
121
122void SkMatrix44::asRowMajord(double dst[]) const {
123 const SkMScalar* src = &fMat[0][0];
124 for (int i = 0; i < 4; ++i) {
125 dst[0] = SkMScalarToDouble(src[0]);
126 dst[4] = SkMScalarToDouble(src[1]);
127 dst[8] = SkMScalarToDouble(src[2]);
128 dst[12] = SkMScalarToDouble(src[3]);
129 src += 4;
130 dst += 1;
131 }
132}
133
vollick@chromium.orgf11cf9f2012-11-19 21:02:06 +0000134void SkMatrix44::setColMajorf(const float src[]) {
135 SkMScalar* dst = &fMat[0][0];
136#ifdef SK_MSCALAR_IS_DOUBLE
137 for (int i = 0; i < 16; ++i) {
138 dst[i] = SkMScalarToFloat(src[i]);
139 }
140#elif defined SK_MSCALAR_IS_FLOAT
141 memcpy(dst, src, 16 * sizeof(float));
142#endif
reed@google.com7d683352012-12-03 21:19:52 +0000143
144 this->dirtyTypeMask();
vollick@chromium.orgf11cf9f2012-11-19 21:02:06 +0000145}
146
147void SkMatrix44::setColMajord(const double src[]) {
148 SkMScalar* dst = &fMat[0][0];
149#ifdef SK_MSCALAR_IS_DOUBLE
150 memcpy(dst, src, 16 * sizeof(double));
151#elif defined SK_MSCALAR_IS_FLOAT
152 for (int i = 0; i < 16; ++i) {
robertphillips@google.com93f03322012-12-03 17:35:19 +0000153 dst[i] = SkDoubleToMScalar(src[i]);
vollick@chromium.orgf11cf9f2012-11-19 21:02:06 +0000154 }
155#endif
reed@google.com7d683352012-12-03 21:19:52 +0000156
157 this->dirtyTypeMask();
vollick@chromium.orgf11cf9f2012-11-19 21:02:06 +0000158}
159
160void SkMatrix44::setRowMajorf(const float src[]) {
161 SkMScalar* dst = &fMat[0][0];
162 for (int i = 0; i < 4; ++i) {
163 dst[0] = SkMScalarToFloat(src[0]);
164 dst[4] = SkMScalarToFloat(src[1]);
165 dst[8] = SkMScalarToFloat(src[2]);
166 dst[12] = SkMScalarToFloat(src[3]);
167 src += 4;
168 dst += 1;
169 }
reed@google.com7d683352012-12-03 21:19:52 +0000170 this->dirtyTypeMask();
vollick@chromium.orgf11cf9f2012-11-19 21:02:06 +0000171}
172
173void SkMatrix44::setRowMajord(const double src[]) {
174 SkMScalar* dst = &fMat[0][0];
175 for (int i = 0; i < 4; ++i) {
robertphillips@google.com93f03322012-12-03 17:35:19 +0000176 dst[0] = SkDoubleToMScalar(src[0]);
177 dst[4] = SkDoubleToMScalar(src[1]);
178 dst[8] = SkDoubleToMScalar(src[2]);
179 dst[12] = SkDoubleToMScalar(src[3]);
vollick@chromium.orgf11cf9f2012-11-19 21:02:06 +0000180 src += 4;
181 dst += 1;
182 }
reed@google.com7d683352012-12-03 21:19:52 +0000183 this->dirtyTypeMask();
vollick@chromium.orgf11cf9f2012-11-19 21:02:06 +0000184}
185
reed@google.comda9fac02011-06-13 14:46:52 +0000186///////////////////////////////////////////////////////////////////////////////
187
reed@google.com7d683352012-12-03 21:19:52 +0000188const SkMatrix44& SkMatrix44::I() {
189 static SkMatrix44 gIdentity;
190 return gIdentity;
reed@google.com8260a892011-06-13 14:02:52 +0000191}
192
reed@google.com8260a892011-06-13 14:02:52 +0000193void SkMatrix44::setIdentity() {
194 sk_bzero(fMat, sizeof(fMat));
195 fMat[0][0] = fMat[1][1] = fMat[2][2] = fMat[3][3] = 1;
reed@google.com7d683352012-12-03 21:19:52 +0000196 this->setTypeMask(kIdentity_Mask);
reed@google.com8260a892011-06-13 14:02:52 +0000197}
198
199void SkMatrix44::set3x3(SkMScalar m00, SkMScalar m01, SkMScalar m02,
200 SkMScalar m10, SkMScalar m11, SkMScalar m12,
201 SkMScalar m20, SkMScalar m21, SkMScalar m22) {
reed@google.com8260a892011-06-13 14:02:52 +0000202 fMat[0][0] = m00; fMat[0][1] = m01; fMat[0][2] = m02; fMat[0][3] = 0;
203 fMat[1][0] = m10; fMat[1][1] = m11; fMat[1][2] = m12; fMat[1][3] = 0;
204 fMat[2][0] = m20; fMat[2][1] = m21; fMat[2][2] = m22; fMat[2][3] = 0;
205 fMat[3][0] = 0; fMat[3][1] = 0; fMat[3][2] = 0; fMat[3][3] = 1;
reed@google.com7d683352012-12-03 21:19:52 +0000206 this->dirtyTypeMask();
reed@google.com8260a892011-06-13 14:02:52 +0000207}
208
209///////////////////////////////////////////////////////////////////////////////
210
211void SkMatrix44::setTranslate(SkMScalar tx, SkMScalar ty, SkMScalar tz) {
212 this->setIdentity();
213 fMat[3][0] = tx;
214 fMat[3][1] = ty;
215 fMat[3][2] = tz;
216 fMat[3][3] = 1;
skia.committer@gmail.come659c2e2012-12-04 02:01:25 +0000217
reed@google.com7d683352012-12-03 21:19:52 +0000218 int mask = kIdentity_Mask;
219 if (0 != tx || 0 != ty || 0 != tz) {
220 mask |= kTranslate_Mask;
221 }
222 this->setTypeMask(mask);
reed@google.com8260a892011-06-13 14:02:52 +0000223}
224
225void SkMatrix44::preTranslate(SkMScalar dx, SkMScalar dy, SkMScalar dz) {
226 SkMatrix44 mat;
227 mat.setTranslate(dx, dy, dz);
228 this->preConcat(mat);
229}
230
231void SkMatrix44::postTranslate(SkMScalar dx, SkMScalar dy, SkMScalar dz) {
232 fMat[3][0] += dx;
233 fMat[3][1] += dy;
234 fMat[3][2] += dz;
reed@google.com7d683352012-12-03 21:19:52 +0000235 this->dirtyTypeMask();
reed@google.com8260a892011-06-13 14:02:52 +0000236}
237
238///////////////////////////////////////////////////////////////////////////////
239
240void SkMatrix44::setScale(SkMScalar sx, SkMScalar sy, SkMScalar sz) {
241 sk_bzero(fMat, sizeof(fMat));
242 fMat[0][0] = sx;
243 fMat[1][1] = sy;
244 fMat[2][2] = sz;
245 fMat[3][3] = 1;
skia.committer@gmail.come659c2e2012-12-04 02:01:25 +0000246
reed@google.com7d683352012-12-03 21:19:52 +0000247 int mask = kIdentity_Mask;
248 if (0 != sx || 0 != sy || 0 != sz) {
249 mask |= kScale_Mask;
250 }
251 this->setTypeMask(mask);
reed@google.com8260a892011-06-13 14:02:52 +0000252}
253
254void SkMatrix44::preScale(SkMScalar sx, SkMScalar sy, SkMScalar sz) {
255 SkMatrix44 tmp;
256 tmp.setScale(sx, sy, sz);
257 this->preConcat(tmp);
258}
259
260void SkMatrix44::postScale(SkMScalar sx, SkMScalar sy, SkMScalar sz) {
261 for (int i = 0; i < 4; i++) {
262 fMat[i][0] *= sx;
263 fMat[i][1] *= sy;
264 fMat[i][2] *= sz;
265 }
reed@google.com7d683352012-12-03 21:19:52 +0000266 this->dirtyTypeMask();
reed@google.com8260a892011-06-13 14:02:52 +0000267}
268
269///////////////////////////////////////////////////////////////////////////////
270
271void SkMatrix44::setRotateAbout(SkMScalar x, SkMScalar y, SkMScalar z,
272 SkMScalar radians) {
reed@google.com7d683352012-12-03 21:19:52 +0000273 double len2 = (double)x * x + (double)y * y + (double)z * z;
274 if (1 != len2) {
275 if (0 == len2) {
reed@google.com8260a892011-06-13 14:02:52 +0000276 this->setIdentity();
277 return;
278 }
279 double scale = 1 / sqrt(len2);
bsalomon@google.com9d12f5c2011-09-29 18:08:18 +0000280 x = SkDoubleToMScalar(x * scale);
281 y = SkDoubleToMScalar(y * scale);
282 z = SkDoubleToMScalar(z * scale);
reed@google.com8260a892011-06-13 14:02:52 +0000283 }
284 this->setRotateAboutUnit(x, y, z, radians);
285}
286
287void SkMatrix44::setRotateAboutUnit(SkMScalar x, SkMScalar y, SkMScalar z,
288 SkMScalar radians) {
289 double c = cos(radians);
290 double s = sin(radians);
291 double C = 1 - c;
292 double xs = x * s;
293 double ys = y * s;
294 double zs = z * s;
295 double xC = x * C;
296 double yC = y * C;
297 double zC = z * C;
298 double xyC = x * yC;
299 double yzC = y * zC;
300 double zxC = z * xC;
301
302 // if you're looking at wikipedia, remember that we're column major.
bsalomon@google.com9d12f5c2011-09-29 18:08:18 +0000303 this->set3x3(SkDoubleToMScalar(x * xC + c), // scale x
304 SkDoubleToMScalar(xyC + zs), // skew x
305 SkDoubleToMScalar(zxC - ys), // trans x
306
307 SkDoubleToMScalar(xyC - zs), // skew y
308 SkDoubleToMScalar(y * yC + c), // scale y
309 SkDoubleToMScalar(yzC + xs), // trans y
310
311 SkDoubleToMScalar(zxC + ys), // persp x
312 SkDoubleToMScalar(yzC - xs), // persp y
313 SkDoubleToMScalar(z * zC + c)); // persp 2
reed@google.com8260a892011-06-13 14:02:52 +0000314}
315
316///////////////////////////////////////////////////////////////////////////////
317
318void SkMatrix44::setConcat(const SkMatrix44& a, const SkMatrix44& b) {
reed@google.com7d683352012-12-03 21:19:52 +0000319 if (a.isIdentity()) {
320 *this = b;
321 return;
322 }
323 if (b.isIdentity()) {
324 *this = a;
325 return;
326 }
327
328 bool useStorage = (this == &a || this == &b);
329 SkMScalar storage[16];
330 SkMScalar* result = useStorage ? storage : &fMat[0][0];
331
332 for (int j = 0; j < 4; j++) {
333 for (int i = 0; i < 4; i++) {
reed@google.com8260a892011-06-13 14:02:52 +0000334 double value = 0;
335 for (int k = 0; k < 4; k++) {
336 value += SkMScalarToDouble(a.fMat[k][i]) * b.fMat[j][k];
337 }
reed@google.com7d683352012-12-03 21:19:52 +0000338 *result++ = SkDoubleToMScalar(value);
reed@google.com8260a892011-06-13 14:02:52 +0000339 }
340 }
reed@google.com7d683352012-12-03 21:19:52 +0000341 if (useStorage) {
342 memcpy(fMat, storage, sizeof(storage));
343 }
344
345 this->dirtyTypeMask();
reed@google.com8260a892011-06-13 14:02:52 +0000346}
347
348///////////////////////////////////////////////////////////////////////////////
349
350static inline SkMScalar det2x2(double m00, double m01, double m10, double m11) {
bsalomon@google.com9d12f5c2011-09-29 18:08:18 +0000351 return SkDoubleToMScalar(m00 * m11 - m10 * m01);
reed@google.com8260a892011-06-13 14:02:52 +0000352}
353
354static inline double det3x3(double m00, double m01, double m02,
355 double m10, double m11, double m12,
356 double m20, double m21, double m22) {
357 return m00 * det2x2(m11, m12, m21, m22) -
358 m10 * det2x2(m01, m02, m21, m22) +
359 m20 * det2x2(m01, m02, m11, m12);
360}
361
362/** We always perform the calculation in doubles, to avoid prematurely losing
363 precision along the way. This relies on the compiler automatically
364 promoting our SkMScalar values to double (if needed).
365 */
366double SkMatrix44::determinant() const {
367 return fMat[0][0] * det3x3(fMat[1][1], fMat[1][2], fMat[1][3],
368 fMat[2][1], fMat[2][2], fMat[2][3],
369 fMat[3][1], fMat[3][2], fMat[3][3]) -
370 fMat[1][0] * det3x3(fMat[0][1], fMat[0][2], fMat[0][3],
371 fMat[2][1], fMat[2][2], fMat[2][3],
372 fMat[3][1], fMat[3][2], fMat[3][3]) +
373 fMat[2][0] * det3x3(fMat[0][1], fMat[0][2], fMat[0][3],
374 fMat[1][1], fMat[1][2], fMat[1][3],
375 fMat[3][1], fMat[3][2], fMat[3][3]) -
376 fMat[3][0] * det3x3(fMat[0][1], fMat[0][2], fMat[0][3],
377 fMat[1][1], fMat[1][2], fMat[1][3],
378 fMat[2][1], fMat[2][2], fMat[2][3]);
379}
380
381///////////////////////////////////////////////////////////////////////////////
382
383// just picked a small value. not sure how to pick the "right" one
384#define TOO_SMALL_FOR_DETERMINANT (1.e-8)
385
386static inline double dabs(double x) {
387 if (x < 0) {
388 x = -x;
389 }
390 return x;
391}
392
393bool SkMatrix44::invert(SkMatrix44* inverse) const {
reed@google.com7d683352012-12-03 21:19:52 +0000394 if (this->isTriviallyIdentity()) {
395 if (inverse) {
396 *inverse = *this;
397 return true;
398 }
399 }
400
reed@google.com8260a892011-06-13 14:02:52 +0000401 double det = this->determinant();
402 if (dabs(det) < TOO_SMALL_FOR_DETERMINANT) {
403 return false;
404 }
reed@google.com7d683352012-12-03 21:19:52 +0000405
406 // We now we will succeed, so return early if the caller doesn't actually
407 // want the computed inverse.
reed@google.com8260a892011-06-13 14:02:52 +0000408 if (NULL == inverse) {
409 return true;
410 }
411
412 // we explicitly promote to doubles to keep the intermediate values in
413 // higher precision (assuming SkMScalar isn't already a double)
414 double m00 = fMat[0][0];
415 double m01 = fMat[0][1];
416 double m02 = fMat[0][2];
417 double m03 = fMat[0][3];
418 double m10 = fMat[1][0];
419 double m11 = fMat[1][1];
420 double m12 = fMat[1][2];
421 double m13 = fMat[1][3];
422 double m20 = fMat[2][0];
423 double m21 = fMat[2][1];
424 double m22 = fMat[2][2];
425 double m23 = fMat[2][3];
426 double m30 = fMat[3][0];
427 double m31 = fMat[3][1];
428 double m32 = fMat[3][2];
429 double m33 = fMat[3][3];
430
431 double tmp[4][4];
432
433 tmp[0][0] = m12*m23*m31 - m13*m22*m31 + m13*m21*m32 - m11*m23*m32 - m12*m21*m33 + m11*m22*m33;
434 tmp[0][1] = m03*m22*m31 - m02*m23*m31 - m03*m21*m32 + m01*m23*m32 + m02*m21*m33 - m01*m22*m33;
435 tmp[0][2] = m02*m13*m31 - m03*m12*m31 + m03*m11*m32 - m01*m13*m32 - m02*m11*m33 + m01*m12*m33;
436 tmp[0][3] = m03*m12*m21 - m02*m13*m21 - m03*m11*m22 + m01*m13*m22 + m02*m11*m23 - m01*m12*m23;
437 tmp[1][0] = m13*m22*m30 - m12*m23*m30 - m13*m20*m32 + m10*m23*m32 + m12*m20*m33 - m10*m22*m33;
438 tmp[1][1] = m02*m23*m30 - m03*m22*m30 + m03*m20*m32 - m00*m23*m32 - m02*m20*m33 + m00*m22*m33;
439 tmp[1][2] = m03*m12*m30 - m02*m13*m30 - m03*m10*m32 + m00*m13*m32 + m02*m10*m33 - m00*m12*m33;
440 tmp[1][3] = m02*m13*m20 - m03*m12*m20 + m03*m10*m22 - m00*m13*m22 - m02*m10*m23 + m00*m12*m23;
441 tmp[2][0] = m11*m23*m30 - m13*m21*m30 + m13*m20*m31 - m10*m23*m31 - m11*m20*m33 + m10*m21*m33;
442 tmp[2][1] = m03*m21*m30 - m01*m23*m30 - m03*m20*m31 + m00*m23*m31 + m01*m20*m33 - m00*m21*m33;
443 tmp[2][2] = m01*m13*m30 - m03*m11*m30 + m03*m10*m31 - m00*m13*m31 - m01*m10*m33 + m00*m11*m33;
444 tmp[2][3] = m03*m11*m20 - m01*m13*m20 - m03*m10*m21 + m00*m13*m21 + m01*m10*m23 - m00*m11*m23;
445 tmp[3][0] = m12*m21*m30 - m11*m22*m30 - m12*m20*m31 + m10*m22*m31 + m11*m20*m32 - m10*m21*m32;
446 tmp[3][1] = m01*m22*m30 - m02*m21*m30 + m02*m20*m31 - m00*m22*m31 - m01*m20*m32 + m00*m21*m32;
447 tmp[3][2] = m02*m11*m30 - m01*m12*m30 - m02*m10*m31 + m00*m12*m31 + m01*m10*m32 - m00*m11*m32;
448 tmp[3][3] = m01*m12*m20 - m02*m11*m20 + m02*m10*m21 - m00*m12*m21 - m01*m10*m22 + m00*m11*m22;
449
450 double invDet = 1.0 / det;
451 for (int i = 0; i < 4; i++) {
452 for (int j = 0; j < 4; j++) {
453 inverse->fMat[i][j] = SkDoubleToMScalar(tmp[i][j] * invDet);
454 }
455 }
reed@google.com7d683352012-12-03 21:19:52 +0000456 inverse->dirtyTypeMask();
reed@google.com8260a892011-06-13 14:02:52 +0000457 return true;
458}
459
460///////////////////////////////////////////////////////////////////////////////
461
vollick@chromium.org9b21c252012-11-14 21:33:55 +0000462void SkMatrix44::transpose() {
463 SkTSwap(fMat[0][1], fMat[1][0]);
464 SkTSwap(fMat[0][2], fMat[2][0]);
465 SkTSwap(fMat[0][3], fMat[3][0]);
466 SkTSwap(fMat[1][2], fMat[2][1]);
467 SkTSwap(fMat[1][3], fMat[3][1]);
468 SkTSwap(fMat[2][3], fMat[3][2]);
reed@google.com7d683352012-12-03 21:19:52 +0000469
470 if (!this->isTriviallyIdentity()) {
471 this->dirtyTypeMask();
472 }
vollick@chromium.org9b21c252012-11-14 21:33:55 +0000473}
474
475///////////////////////////////////////////////////////////////////////////////
476
reed@google.com1ea95be2012-11-09 21:39:48 +0000477void SkMatrix44::mapScalars(const SkScalar src[4], SkScalar dst[4]) const {
reed@google.com7d683352012-12-03 21:19:52 +0000478 SkScalar storage[4];
479 SkScalar* result = (src == dst) ? storage : dst;
480
reed@google.com8260a892011-06-13 14:02:52 +0000481 for (int i = 0; i < 4; i++) {
482 SkMScalar value = 0;
483 for (int j = 0; j < 4; j++) {
484 value += fMat[j][i] * src[j];
485 }
bsalomon@google.com72e49b82011-10-27 21:47:03 +0000486 result[i] = SkMScalarToScalar(value);
reed@google.com8260a892011-06-13 14:02:52 +0000487 }
skia.committer@gmail.come659c2e2012-12-04 02:01:25 +0000488
reed@google.com7d683352012-12-03 21:19:52 +0000489 if (storage == result) {
490 memcpy(dst, storage, sizeof(storage));
491 }
reed@google.com8260a892011-06-13 14:02:52 +0000492}
493
reed@google.com1ea95be2012-11-09 21:39:48 +0000494#ifdef SK_MSCALAR_IS_DOUBLE
reed@google.com7d683352012-12-03 21:19:52 +0000495
reed@google.com1ea95be2012-11-09 21:39:48 +0000496void SkMatrix44::mapMScalars(const SkMScalar src[4], SkMScalar dst[4]) const {
reed@google.com7d683352012-12-03 21:19:52 +0000497 SkMScalar storage[4];
498 SkMScalar* result = (src == dst) ? storage : dst;
skia.committer@gmail.come659c2e2012-12-04 02:01:25 +0000499
reed@google.com1ea95be2012-11-09 21:39:48 +0000500 for (int i = 0; i < 4; i++) {
501 SkMScalar value = 0;
502 for (int j = 0; j < 4; j++) {
503 value += fMat[j][i] * src[j];
504 }
reed@google.com7d683352012-12-03 21:19:52 +0000505 result[i] = value;
reed@google.com1ea95be2012-11-09 21:39:48 +0000506 }
skia.committer@gmail.come659c2e2012-12-04 02:01:25 +0000507
reed@google.com7d683352012-12-03 21:19:52 +0000508 if (storage == result) {
509 memcpy(dst, storage, sizeof(storage));
510 }
reed@google.com1ea95be2012-11-09 21:39:48 +0000511}
reed@google.com7d683352012-12-03 21:19:52 +0000512
reed@google.com1ea95be2012-11-09 21:39:48 +0000513#endif
514
reed@google.com8260a892011-06-13 14:02:52 +0000515///////////////////////////////////////////////////////////////////////////////
516
517void SkMatrix44::dump() const {
tomhudson@google.com9ac4a892011-06-28 13:53:13 +0000518 static const char* format =
519 "[%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 +0000520#if 0
tomhudson@google.com9ac4a892011-06-28 13:53:13 +0000521 SkDebugf(format,
reed@google.com8260a892011-06-13 14:02:52 +0000522 fMat[0][0], fMat[1][0], fMat[2][0], fMat[3][0],
523 fMat[0][1], fMat[1][1], fMat[2][1], fMat[3][1],
524 fMat[0][2], fMat[1][2], fMat[2][2], fMat[3][2],
525 fMat[0][3], fMat[1][3], fMat[2][3], fMat[3][3]);
tomhudson@google.com9ac4a892011-06-28 13:53:13 +0000526#else
527 SkDebugf(format,
528 fMat[0][0], fMat[0][1], fMat[0][2], fMat[0][3],
529 fMat[1][0], fMat[1][1], fMat[1][2], fMat[1][3],
530 fMat[2][0], fMat[2][1], fMat[2][2], fMat[2][3],
531 fMat[3][0], fMat[3][1], fMat[3][2], fMat[3][3]);
reed@google.com8260a892011-06-13 14:02:52 +0000532#endif
533}
534
535///////////////////////////////////////////////////////////////////////////////
536
reed@google.com7d683352012-12-03 21:19:52 +0000537// TODO: make this support src' perspective elements
538//
reed@google.com8260a892011-06-13 14:02:52 +0000539static void initFromMatrix(SkMScalar dst[4][4], const SkMatrix& src) {
540 sk_bzero(dst, 16 * sizeof(SkMScalar));
bsalomon@google.com72e49b82011-10-27 21:47:03 +0000541 dst[0][0] = SkScalarToMScalar(src[SkMatrix::kMScaleX]);
542 dst[1][0] = SkScalarToMScalar(src[SkMatrix::kMSkewX]);
543 dst[3][0] = SkScalarToMScalar(src[SkMatrix::kMTransX]);
544 dst[0][1] = SkScalarToMScalar(src[SkMatrix::kMSkewY]);
545 dst[1][1] = SkScalarToMScalar(src[SkMatrix::kMScaleY]);
546 dst[3][1] = SkScalarToMScalar(src[SkMatrix::kMTransY]);
reed@google.com8260a892011-06-13 14:02:52 +0000547 dst[2][2] = dst[3][3] = 1;
548}
549
550SkMatrix44::SkMatrix44(const SkMatrix& src) {
551 initFromMatrix(fMat, src);
552}
553
554SkMatrix44& SkMatrix44::operator=(const SkMatrix& src) {
555 initFromMatrix(fMat, src);
reed@google.com7d683352012-12-03 21:19:52 +0000556
557 if (src.isIdentity()) {
558 this->setTypeMask(kIdentity_Mask);
559 } else {
560 this->dirtyTypeMask();
561 }
reed@google.com8260a892011-06-13 14:02:52 +0000562 return *this;
563}
564
reed@google.com7d683352012-12-03 21:19:52 +0000565// TODO: make this support our perspective elements
566//
reed@google.com8260a892011-06-13 14:02:52 +0000567SkMatrix44::operator SkMatrix() const {
568 SkMatrix dst;
569 dst.reset(); // setup our perspective correctly for identity
570
bsalomon@google.com72e49b82011-10-27 21:47:03 +0000571 dst[SkMatrix::kMScaleX] = SkMScalarToScalar(fMat[0][0]);
572 dst[SkMatrix::kMSkewX] = SkMScalarToScalar(fMat[1][0]);
573 dst[SkMatrix::kMTransX] = SkMScalarToScalar(fMat[3][0]);
reed@google.com8260a892011-06-13 14:02:52 +0000574
bsalomon@google.com72e49b82011-10-27 21:47:03 +0000575 dst[SkMatrix::kMSkewY] = SkMScalarToScalar(fMat[0][1]);
576 dst[SkMatrix::kMScaleY] = SkMScalarToScalar(fMat[1][1]);
577 dst[SkMatrix::kMTransY] = SkMScalarToScalar(fMat[3][1]);
reed@google.com8260a892011-06-13 14:02:52 +0000578
579 return dst;
580}