blob: 42c38f7b4fa5e67bad698d14ada41c41c0544d2c [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
13SkMatrix44::SkMatrix44() {
14 this->setIdentity();
15}
16
17SkMatrix44::SkMatrix44(const SkMatrix44& src) {
18 memcpy(this, &src, sizeof(src));
19}
20
21SkMatrix44::SkMatrix44(const SkMatrix44& a, const SkMatrix44& b) {
22 this->setConcat(a, b);
23}
24
25SkMScalar SkMatrix44::get(int row, int col) const {
26 SkASSERT(row <= 3 && row >= 0);
27 SkASSERT(col <= 3 && col >= 0);
28 return fMat[col][row];
29}
30
31void SkMatrix44::set(int row, int col, const SkMScalar& value) {
32 SkASSERT(row <= 3 && row >= 0);
33 SkASSERT(col <= 3 && col >= 0);
34 fMat[col][row] = value;
35}
36
37///////////////////////////////////////////////////////////////////////////////
38
reed@google.comda9fac02011-06-13 14:46:52 +000039void SkMatrix44::asColMajorf(float dst[]) const {
40 const SkMScalar* src = &fMat[0][0];
41#ifdef SK_MSCALAR_IS_DOUBLE
42 for (int i = 0; i < 16; ++i) {
43 dst[i] = SkMScalarToFloat(src[i]);
44 }
vollick@chromium.org5596a692012-11-13 20:12:00 +000045#elif defined SK_MSCALAR_IS_FLOAT
reed@google.comda9fac02011-06-13 14:46:52 +000046 memcpy(dst, src, 16 * sizeof(float));
47#endif
48}
49
50void SkMatrix44::asColMajord(double dst[]) const {
51 const SkMScalar* src = &fMat[0][0];
52#ifdef SK_MSCALAR_IS_DOUBLE
53 memcpy(dst, src, 16 * sizeof(double));
vollick@chromium.org5596a692012-11-13 20:12:00 +000054#elif defined SK_MSCALAR_IS_FLOAT
reed@google.comda9fac02011-06-13 14:46:52 +000055 for (int i = 0; i < 16; ++i) {
56 dst[i] = SkMScalarToDouble(src[i]);
57 }
58#endif
59}
60
61void SkMatrix44::asRowMajorf(float dst[]) const {
62 const SkMScalar* src = &fMat[0][0];
63 for (int i = 0; i < 4; ++i) {
64 dst[0] = SkMScalarToFloat(src[0]);
65 dst[4] = SkMScalarToFloat(src[1]);
66 dst[8] = SkMScalarToFloat(src[2]);
67 dst[12] = SkMScalarToFloat(src[3]);
68 src += 4;
69 dst += 1;
70 }
71}
72
73void SkMatrix44::asRowMajord(double dst[]) const {
74 const SkMScalar* src = &fMat[0][0];
75 for (int i = 0; i < 4; ++i) {
76 dst[0] = SkMScalarToDouble(src[0]);
77 dst[4] = SkMScalarToDouble(src[1]);
78 dst[8] = SkMScalarToDouble(src[2]);
79 dst[12] = SkMScalarToDouble(src[3]);
80 src += 4;
81 dst += 1;
82 }
83}
84
vollick@chromium.orgf11cf9f2012-11-19 21:02:06 +000085void SkMatrix44::setColMajorf(const float src[]) {
86 SkMScalar* dst = &fMat[0][0];
87#ifdef SK_MSCALAR_IS_DOUBLE
88 for (int i = 0; i < 16; ++i) {
89 dst[i] = SkMScalarToFloat(src[i]);
90 }
91#elif defined SK_MSCALAR_IS_FLOAT
92 memcpy(dst, src, 16 * sizeof(float));
93#endif
94}
95
96void SkMatrix44::setColMajord(const double src[]) {
97 SkMScalar* dst = &fMat[0][0];
98#ifdef SK_MSCALAR_IS_DOUBLE
99 memcpy(dst, src, 16 * sizeof(double));
100#elif defined SK_MSCALAR_IS_FLOAT
101 for (int i = 0; i < 16; ++i) {
102 dst[i] = SkMScalarToDouble(src[i]);
103 }
104#endif
105}
106
107void SkMatrix44::setRowMajorf(const float src[]) {
108 SkMScalar* dst = &fMat[0][0];
109 for (int i = 0; i < 4; ++i) {
110 dst[0] = SkMScalarToFloat(src[0]);
111 dst[4] = SkMScalarToFloat(src[1]);
112 dst[8] = SkMScalarToFloat(src[2]);
113 dst[12] = SkMScalarToFloat(src[3]);
114 src += 4;
115 dst += 1;
116 }
117}
118
119void SkMatrix44::setRowMajord(const double src[]) {
120 SkMScalar* dst = &fMat[0][0];
121 for (int i = 0; i < 4; ++i) {
122 dst[0] = SkMScalarToDouble(src[0]);
123 dst[4] = SkMScalarToDouble(src[1]);
124 dst[8] = SkMScalarToDouble(src[2]);
125 dst[12] = SkMScalarToDouble(src[3]);
126 src += 4;
127 dst += 1;
128 }
129}
130
reed@google.comda9fac02011-06-13 14:46:52 +0000131///////////////////////////////////////////////////////////////////////////////
132
reed@google.com8260a892011-06-13 14:02:52 +0000133bool SkMatrix44::isIdentity() const {
digit@google.com3e05f292012-01-10 10:00:59 +0000134 static const SkMScalar sIdentityMat[4][4] = {
135 { 1, 0, 0, 0 },
136 { 0, 1, 0, 0 },
137 { 0, 0, 1, 0 },
138 { 0, 0, 0, 1 },
139 };
140 return !memcmp(fMat, sIdentityMat, sizeof(fMat));
reed@google.com8260a892011-06-13 14:02:52 +0000141}
142
143///////////////////////////////////////////////////////////////////////////////
144
145void SkMatrix44::setIdentity() {
146 sk_bzero(fMat, sizeof(fMat));
147 fMat[0][0] = fMat[1][1] = fMat[2][2] = fMat[3][3] = 1;
148}
149
150void SkMatrix44::set3x3(SkMScalar m00, SkMScalar m01, SkMScalar m02,
151 SkMScalar m10, SkMScalar m11, SkMScalar m12,
152 SkMScalar m20, SkMScalar m21, SkMScalar m22) {
153 sk_bzero(fMat, sizeof(fMat));
154 fMat[0][0] = m00; fMat[0][1] = m01; fMat[0][2] = m02; fMat[0][3] = 0;
155 fMat[1][0] = m10; fMat[1][1] = m11; fMat[1][2] = m12; fMat[1][3] = 0;
156 fMat[2][0] = m20; fMat[2][1] = m21; fMat[2][2] = m22; fMat[2][3] = 0;
157 fMat[3][0] = 0; fMat[3][1] = 0; fMat[3][2] = 0; fMat[3][3] = 1;
158}
159
160///////////////////////////////////////////////////////////////////////////////
161
162void SkMatrix44::setTranslate(SkMScalar tx, SkMScalar ty, SkMScalar tz) {
163 this->setIdentity();
164 fMat[3][0] = tx;
165 fMat[3][1] = ty;
166 fMat[3][2] = tz;
167 fMat[3][3] = 1;
168}
169
170void SkMatrix44::preTranslate(SkMScalar dx, SkMScalar dy, SkMScalar dz) {
171 SkMatrix44 mat;
172 mat.setTranslate(dx, dy, dz);
173 this->preConcat(mat);
174}
175
176void SkMatrix44::postTranslate(SkMScalar dx, SkMScalar dy, SkMScalar dz) {
177 fMat[3][0] += dx;
178 fMat[3][1] += dy;
179 fMat[3][2] += dz;
180}
181
182///////////////////////////////////////////////////////////////////////////////
183
184void SkMatrix44::setScale(SkMScalar sx, SkMScalar sy, SkMScalar sz) {
185 sk_bzero(fMat, sizeof(fMat));
186 fMat[0][0] = sx;
187 fMat[1][1] = sy;
188 fMat[2][2] = sz;
189 fMat[3][3] = 1;
190}
191
192void SkMatrix44::preScale(SkMScalar sx, SkMScalar sy, SkMScalar sz) {
193 SkMatrix44 tmp;
194 tmp.setScale(sx, sy, sz);
195 this->preConcat(tmp);
196}
197
198void SkMatrix44::postScale(SkMScalar sx, SkMScalar sy, SkMScalar sz) {
199 for (int i = 0; i < 4; i++) {
200 fMat[i][0] *= sx;
201 fMat[i][1] *= sy;
202 fMat[i][2] *= sz;
203 }
204}
205
206///////////////////////////////////////////////////////////////////////////////
207
208void SkMatrix44::setRotateAbout(SkMScalar x, SkMScalar y, SkMScalar z,
209 SkMScalar radians) {
210 double len2 = x * x + y * y + z * z;
211 if (len2 != 1) {
212 if (len2 == 0) {
213 this->setIdentity();
214 return;
215 }
216 double scale = 1 / sqrt(len2);
bsalomon@google.com9d12f5c2011-09-29 18:08:18 +0000217 x = SkDoubleToMScalar(x * scale);
218 y = SkDoubleToMScalar(y * scale);
219 z = SkDoubleToMScalar(z * scale);
reed@google.com8260a892011-06-13 14:02:52 +0000220 }
221 this->setRotateAboutUnit(x, y, z, radians);
222}
223
224void SkMatrix44::setRotateAboutUnit(SkMScalar x, SkMScalar y, SkMScalar z,
225 SkMScalar radians) {
226 double c = cos(radians);
227 double s = sin(radians);
228 double C = 1 - c;
229 double xs = x * s;
230 double ys = y * s;
231 double zs = z * s;
232 double xC = x * C;
233 double yC = y * C;
234 double zC = z * C;
235 double xyC = x * yC;
236 double yzC = y * zC;
237 double zxC = z * xC;
238
239 // if you're looking at wikipedia, remember that we're column major.
bsalomon@google.com9d12f5c2011-09-29 18:08:18 +0000240 this->set3x3(SkDoubleToMScalar(x * xC + c), // scale x
241 SkDoubleToMScalar(xyC + zs), // skew x
242 SkDoubleToMScalar(zxC - ys), // trans x
243
244 SkDoubleToMScalar(xyC - zs), // skew y
245 SkDoubleToMScalar(y * yC + c), // scale y
246 SkDoubleToMScalar(yzC + xs), // trans y
247
248 SkDoubleToMScalar(zxC + ys), // persp x
249 SkDoubleToMScalar(yzC - xs), // persp y
250 SkDoubleToMScalar(z * zC + c)); // persp 2
reed@google.com8260a892011-06-13 14:02:52 +0000251}
252
253///////////////////////////////////////////////////////////////////////////////
254
255void SkMatrix44::setConcat(const SkMatrix44& a, const SkMatrix44& b) {
256 SkMScalar result[4][4];
257 for (int i = 0; i < 4; i++) {
258 for (int j = 0; j < 4; j++) {
259 double value = 0;
260 for (int k = 0; k < 4; k++) {
261 value += SkMScalarToDouble(a.fMat[k][i]) * b.fMat[j][k];
262 }
263 result[j][i] = SkDoubleToMScalar(value);
264 }
265 }
266 memcpy(fMat, result, sizeof(result));
267}
268
269///////////////////////////////////////////////////////////////////////////////
270
271static inline SkMScalar det2x2(double m00, double m01, double m10, double m11) {
bsalomon@google.com9d12f5c2011-09-29 18:08:18 +0000272 return SkDoubleToMScalar(m00 * m11 - m10 * m01);
reed@google.com8260a892011-06-13 14:02:52 +0000273}
274
275static inline double det3x3(double m00, double m01, double m02,
276 double m10, double m11, double m12,
277 double m20, double m21, double m22) {
278 return m00 * det2x2(m11, m12, m21, m22) -
279 m10 * det2x2(m01, m02, m21, m22) +
280 m20 * det2x2(m01, m02, m11, m12);
281}
282
283/** We always perform the calculation in doubles, to avoid prematurely losing
284 precision along the way. This relies on the compiler automatically
285 promoting our SkMScalar values to double (if needed).
286 */
287double SkMatrix44::determinant() const {
288 return fMat[0][0] * det3x3(fMat[1][1], fMat[1][2], fMat[1][3],
289 fMat[2][1], fMat[2][2], fMat[2][3],
290 fMat[3][1], fMat[3][2], fMat[3][3]) -
291 fMat[1][0] * det3x3(fMat[0][1], fMat[0][2], fMat[0][3],
292 fMat[2][1], fMat[2][2], fMat[2][3],
293 fMat[3][1], fMat[3][2], fMat[3][3]) +
294 fMat[2][0] * det3x3(fMat[0][1], fMat[0][2], fMat[0][3],
295 fMat[1][1], fMat[1][2], fMat[1][3],
296 fMat[3][1], fMat[3][2], fMat[3][3]) -
297 fMat[3][0] * det3x3(fMat[0][1], fMat[0][2], fMat[0][3],
298 fMat[1][1], fMat[1][2], fMat[1][3],
299 fMat[2][1], fMat[2][2], fMat[2][3]);
300}
301
302///////////////////////////////////////////////////////////////////////////////
303
304// just picked a small value. not sure how to pick the "right" one
305#define TOO_SMALL_FOR_DETERMINANT (1.e-8)
306
307static inline double dabs(double x) {
308 if (x < 0) {
309 x = -x;
310 }
311 return x;
312}
313
314bool SkMatrix44::invert(SkMatrix44* inverse) const {
315 double det = this->determinant();
316 if (dabs(det) < TOO_SMALL_FOR_DETERMINANT) {
317 return false;
318 }
319 if (NULL == inverse) {
320 return true;
321 }
322
323 // we explicitly promote to doubles to keep the intermediate values in
324 // higher precision (assuming SkMScalar isn't already a double)
325 double m00 = fMat[0][0];
326 double m01 = fMat[0][1];
327 double m02 = fMat[0][2];
328 double m03 = fMat[0][3];
329 double m10 = fMat[1][0];
330 double m11 = fMat[1][1];
331 double m12 = fMat[1][2];
332 double m13 = fMat[1][3];
333 double m20 = fMat[2][0];
334 double m21 = fMat[2][1];
335 double m22 = fMat[2][2];
336 double m23 = fMat[2][3];
337 double m30 = fMat[3][0];
338 double m31 = fMat[3][1];
339 double m32 = fMat[3][2];
340 double m33 = fMat[3][3];
341
342 double tmp[4][4];
343
344 tmp[0][0] = m12*m23*m31 - m13*m22*m31 + m13*m21*m32 - m11*m23*m32 - m12*m21*m33 + m11*m22*m33;
345 tmp[0][1] = m03*m22*m31 - m02*m23*m31 - m03*m21*m32 + m01*m23*m32 + m02*m21*m33 - m01*m22*m33;
346 tmp[0][2] = m02*m13*m31 - m03*m12*m31 + m03*m11*m32 - m01*m13*m32 - m02*m11*m33 + m01*m12*m33;
347 tmp[0][3] = m03*m12*m21 - m02*m13*m21 - m03*m11*m22 + m01*m13*m22 + m02*m11*m23 - m01*m12*m23;
348 tmp[1][0] = m13*m22*m30 - m12*m23*m30 - m13*m20*m32 + m10*m23*m32 + m12*m20*m33 - m10*m22*m33;
349 tmp[1][1] = m02*m23*m30 - m03*m22*m30 + m03*m20*m32 - m00*m23*m32 - m02*m20*m33 + m00*m22*m33;
350 tmp[1][2] = m03*m12*m30 - m02*m13*m30 - m03*m10*m32 + m00*m13*m32 + m02*m10*m33 - m00*m12*m33;
351 tmp[1][3] = m02*m13*m20 - m03*m12*m20 + m03*m10*m22 - m00*m13*m22 - m02*m10*m23 + m00*m12*m23;
352 tmp[2][0] = m11*m23*m30 - m13*m21*m30 + m13*m20*m31 - m10*m23*m31 - m11*m20*m33 + m10*m21*m33;
353 tmp[2][1] = m03*m21*m30 - m01*m23*m30 - m03*m20*m31 + m00*m23*m31 + m01*m20*m33 - m00*m21*m33;
354 tmp[2][2] = m01*m13*m30 - m03*m11*m30 + m03*m10*m31 - m00*m13*m31 - m01*m10*m33 + m00*m11*m33;
355 tmp[2][3] = m03*m11*m20 - m01*m13*m20 - m03*m10*m21 + m00*m13*m21 + m01*m10*m23 - m00*m11*m23;
356 tmp[3][0] = m12*m21*m30 - m11*m22*m30 - m12*m20*m31 + m10*m22*m31 + m11*m20*m32 - m10*m21*m32;
357 tmp[3][1] = m01*m22*m30 - m02*m21*m30 + m02*m20*m31 - m00*m22*m31 - m01*m20*m32 + m00*m21*m32;
358 tmp[3][2] = m02*m11*m30 - m01*m12*m30 - m02*m10*m31 + m00*m12*m31 + m01*m10*m32 - m00*m11*m32;
359 tmp[3][3] = m01*m12*m20 - m02*m11*m20 + m02*m10*m21 - m00*m12*m21 - m01*m10*m22 + m00*m11*m22;
360
361 double invDet = 1.0 / det;
362 for (int i = 0; i < 4; i++) {
363 for (int j = 0; j < 4; j++) {
364 inverse->fMat[i][j] = SkDoubleToMScalar(tmp[i][j] * invDet);
365 }
366 }
367 return true;
368}
369
370///////////////////////////////////////////////////////////////////////////////
371
vollick@chromium.org9b21c252012-11-14 21:33:55 +0000372void SkMatrix44::transpose() {
373 SkTSwap(fMat[0][1], fMat[1][0]);
374 SkTSwap(fMat[0][2], fMat[2][0]);
375 SkTSwap(fMat[0][3], fMat[3][0]);
376 SkTSwap(fMat[1][2], fMat[2][1]);
377 SkTSwap(fMat[1][3], fMat[3][1]);
378 SkTSwap(fMat[2][3], fMat[3][2]);
379}
380
381///////////////////////////////////////////////////////////////////////////////
382
reed@google.com1ea95be2012-11-09 21:39:48 +0000383void SkMatrix44::mapScalars(const SkScalar src[4], SkScalar dst[4]) const {
reed@google.com8260a892011-06-13 14:02:52 +0000384 SkScalar result[4];
385 for (int i = 0; i < 4; i++) {
386 SkMScalar value = 0;
387 for (int j = 0; j < 4; j++) {
388 value += fMat[j][i] * src[j];
389 }
bsalomon@google.com72e49b82011-10-27 21:47:03 +0000390 result[i] = SkMScalarToScalar(value);
reed@google.com8260a892011-06-13 14:02:52 +0000391 }
392 memcpy(dst, result, sizeof(result));
393}
394
reed@google.com1ea95be2012-11-09 21:39:48 +0000395#ifdef SK_MSCALAR_IS_DOUBLE
396void SkMatrix44::mapMScalars(const SkMScalar src[4], SkMScalar dst[4]) const {
397 SkMScalar result[4];
398 for (int i = 0; i < 4; i++) {
399 SkMScalar value = 0;
400 for (int j = 0; j < 4; j++) {
401 value += fMat[j][i] * src[j];
402 }
403 result[i] = SkMScalarToScalar(value);
404 }
405 memcpy(dst, result, sizeof(result));
406}
407#endif
408
reed@google.com8260a892011-06-13 14:02:52 +0000409///////////////////////////////////////////////////////////////////////////////
410
411void SkMatrix44::dump() const {
tomhudson@google.com9ac4a892011-06-28 13:53:13 +0000412 static const char* format =
413 "[%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 +0000414#if 0
tomhudson@google.com9ac4a892011-06-28 13:53:13 +0000415 SkDebugf(format,
reed@google.com8260a892011-06-13 14:02:52 +0000416 fMat[0][0], fMat[1][0], fMat[2][0], fMat[3][0],
417 fMat[0][1], fMat[1][1], fMat[2][1], fMat[3][1],
418 fMat[0][2], fMat[1][2], fMat[2][2], fMat[3][2],
419 fMat[0][3], fMat[1][3], fMat[2][3], fMat[3][3]);
tomhudson@google.com9ac4a892011-06-28 13:53:13 +0000420#else
421 SkDebugf(format,
422 fMat[0][0], fMat[0][1], fMat[0][2], fMat[0][3],
423 fMat[1][0], fMat[1][1], fMat[1][2], fMat[1][3],
424 fMat[2][0], fMat[2][1], fMat[2][2], fMat[2][3],
425 fMat[3][0], fMat[3][1], fMat[3][2], fMat[3][3]);
reed@google.com8260a892011-06-13 14:02:52 +0000426#endif
427}
428
429///////////////////////////////////////////////////////////////////////////////
430
431static void initFromMatrix(SkMScalar dst[4][4], const SkMatrix& src) {
432 sk_bzero(dst, 16 * sizeof(SkMScalar));
bsalomon@google.com72e49b82011-10-27 21:47:03 +0000433 dst[0][0] = SkScalarToMScalar(src[SkMatrix::kMScaleX]);
434 dst[1][0] = SkScalarToMScalar(src[SkMatrix::kMSkewX]);
435 dst[3][0] = SkScalarToMScalar(src[SkMatrix::kMTransX]);
436 dst[0][1] = SkScalarToMScalar(src[SkMatrix::kMSkewY]);
437 dst[1][1] = SkScalarToMScalar(src[SkMatrix::kMScaleY]);
438 dst[3][1] = SkScalarToMScalar(src[SkMatrix::kMTransY]);
reed@google.com8260a892011-06-13 14:02:52 +0000439 dst[2][2] = dst[3][3] = 1;
440}
441
442SkMatrix44::SkMatrix44(const SkMatrix& src) {
443 initFromMatrix(fMat, src);
444}
445
446SkMatrix44& SkMatrix44::operator=(const SkMatrix& src) {
447 initFromMatrix(fMat, src);
448 return *this;
449}
450
451SkMatrix44::operator SkMatrix() const {
452 SkMatrix dst;
453 dst.reset(); // setup our perspective correctly for identity
454
bsalomon@google.com72e49b82011-10-27 21:47:03 +0000455 dst[SkMatrix::kMScaleX] = SkMScalarToScalar(fMat[0][0]);
456 dst[SkMatrix::kMSkewX] = SkMScalarToScalar(fMat[1][0]);
457 dst[SkMatrix::kMTransX] = SkMScalarToScalar(fMat[3][0]);
reed@google.com8260a892011-06-13 14:02:52 +0000458
bsalomon@google.com72e49b82011-10-27 21:47:03 +0000459 dst[SkMatrix::kMSkewY] = SkMScalarToScalar(fMat[0][1]);
460 dst[SkMatrix::kMScaleY] = SkMScalarToScalar(fMat[1][1]);
461 dst[SkMatrix::kMTransY] = SkMScalarToScalar(fMat[3][1]);
reed@google.com8260a892011-06-13 14:02:52 +0000462
463 return dst;
464}