blob: 9ee746a17e847aedbe63401245010a67d08d2b92 [file] [log] [blame]
reed@android.com6d342a42010-02-23 20:18:17 +00001#include "SkMatrix44.h"
2
3SkMatrix44::SkMatrix44() {
4 this->setIdentity();
5}
6
7SkMatrix44::SkMatrix44(const SkMatrix44& src) {
8 memcpy(this, &src, sizeof(src));
9}
10
11SkMatrix44::SkMatrix44(const SkMatrix44& a, const SkMatrix44& b) {
12 this->setConcat(a, b);
13}
14
15///////////////////////////////////////////////////////////////////////////////
16
17void SkMatrix44::setIdentity() {
18 sk_bzero(fMat, sizeof(fMat));
19 fMat[0][0] = fMat[1][1] = fMat[2][2] = fMat[3][3] = SK_MScalar1;
20}
21
22void SkMatrix44::setTranslate(SkMScalar tx, SkMScalar ty, SkMScalar tz) {
23 sk_bzero(fMat, sizeof(fMat));
24 fMat[3][0] = tx;
25 fMat[3][1] = ty;
26 fMat[3][2] = tz;
27 fMat[3][3] = SK_MScalar1;
28}
29
30void SkMatrix44::preTranslate(SkMScalar dx, SkMScalar dy, SkMScalar dz) {
31 SkMatrix44 mat;
32 mat.setTranslate(dx, dy, dz);
33 this->preConcat(mat);
34}
35
36void SkMatrix44::postTranslate(SkMScalar dx, SkMScalar dy, SkMScalar dz) {
37 fMat[3][0] += dx;
38 fMat[3][1] += dy;
39 fMat[3][2] += dz;
40}
41
42///////////////////////////////////////////////////////////////////////////////
43
44void SkMatrix44::setScale(SkMScalar sx, SkMScalar sy, SkMScalar sz) {
45 sk_bzero(fMat, sizeof(fMat));
46 fMat[0][0] = sx;
47 fMat[1][1] = sy;
48 fMat[2][2] = sz;
49 fMat[3][3] = SK_MScalar1;
50}
51
52void SkMatrix44::preScale(SkMScalar sx, SkMScalar sy, SkMScalar sz) {
53 SkMatrix44 tmp;
54 tmp.setScale(sx, sy, sz);
55 this->preConcat(tmp);
56}
57
58void SkMatrix44::postScale(SkMScalar sx, SkMScalar sy, SkMScalar sz) {
59 for (int i = 0; i < 4; i++) {
60 fMat[i][0] *= sx;
61 fMat[i][1] *= sy;
62 fMat[i][2] *= sz;
63 }
64}
65
66///////////////////////////////////////////////////////////////////////////////
67
68void SkMatrix44::setConcat(const SkMatrix44& a, const SkMatrix44& b) {
69 SkMScalar result[4][4];
70 for (int i = 0; i < 4; i++) {
71 for (int j = 0; j < 4; j++) {
72 double value = 0;
73 for (int k = 0; k < 4; k++) {
74 value += (double)a.fMat[k][j] * b.fMat[i][k];
75 }
76 result[j][i] = SkDoubleToMScalar(value);
77 }
78 }
79 memcpy(fMat, result, sizeof(result));
80}
81
82///////////////////////////////////////////////////////////////////////////////
83
84static inline SkMScalar det2x2(double m00, double m01, double m10, double m11) {
85 return m00 * m11 - m10 * m01;
86}
87
88static inline double det3x3(double m00, double m01, double m02,
89 double m10, double m11, double m12,
90 double m20, double m21, double m22) {
91 return m00 * det2x2(m11, m12, m21, m22) -
92 m10 * det2x2(m01, m02, m21, m22) +
93 m20 * det2x2(m01, m02, m11, m12);
94}
95
96/** We always perform the calculation in doubles, to avoid prematurely losing
97 precision along the way. This relies on the compiler automatically
98 promoting our SkMScalar values to double (if needed).
99 */
100double SkMatrix44::determinant() const {
101 return fMat[0][0] * det3x3(fMat[1][1], fMat[1][2], fMat[1][3],
102 fMat[2][1], fMat[2][2], fMat[2][3],
103 fMat[3][1], fMat[3][2], fMat[3][3]) -
104 fMat[1][0] * det3x3(fMat[0][1], fMat[0][2], fMat[0][3],
105 fMat[2][1], fMat[2][2], fMat[2][3],
106 fMat[3][1], fMat[3][2], fMat[3][3]) +
107 fMat[2][0] * det3x3(fMat[0][1], fMat[0][2], fMat[0][3],
108 fMat[1][1], fMat[1][2], fMat[1][3],
109 fMat[3][1], fMat[3][2], fMat[3][3]) -
110 fMat[3][0] * det3x3(fMat[0][1], fMat[0][2], fMat[0][3],
111 fMat[1][1], fMat[1][2], fMat[1][3],
112 fMat[2][1], fMat[2][2], fMat[2][3]);
113}
114
115///////////////////////////////////////////////////////////////////////////////
116
117// just picked a small value. not sure how to pick the "right" one
118#define TOO_SMALL_FOR_DETERMINANT (1.e-8)
119
120static inline double dabs(double x) {
121 if (x < 0) {
122 x = -x;
123 }
124 return x;
125}
126
127bool SkMatrix44::invert(SkMatrix44* inverse) const {
128 double det = this->determinant();
129 if (dabs(det) < TOO_SMALL_FOR_DETERMINANT) {
130 return false;
131 }
132 if (NULL == inverse) {
133 return true;
134 }
135
136 // we explicitly promote to doubles to keep the intermediate values in
137 // higher precision (assuming SkMScalar isn't already a double)
138 double m00 = fMat[0][0];
139 double m01 = fMat[0][1];
140 double m02 = fMat[0][2];
141 double m03 = fMat[0][3];
142 double m10 = fMat[1][0];
143 double m11 = fMat[1][1];
144 double m12 = fMat[1][2];
145 double m13 = fMat[1][3];
146 double m20 = fMat[2][0];
147 double m21 = fMat[2][1];
148 double m22 = fMat[2][2];
149 double m23 = fMat[2][3];
150 double m30 = fMat[3][0];
151 double m31 = fMat[3][1];
152 double m32 = fMat[3][2];
153 double m33 = fMat[3][3];
154
155 double tmp[4][4];
156
157 tmp[0][0] = m12*m23*m31 - m13*m22*m31 + m13*m21*m32 - m11*m23*m32 - m12*m21*m33 + m11*m22*m33;
158 tmp[0][1] = m03*m22*m31 - m02*m23*m31 - m03*m21*m32 + m01*m23*m32 + m02*m21*m33 - m01*m22*m33;
159 tmp[0][2] = m02*m13*m31 - m03*m12*m31 + m03*m11*m32 - m01*m13*m32 - m02*m11*m33 + m01*m12*m33;
160 tmp[0][3] = m03*m12*m21 - m02*m13*m21 - m03*m11*m22 + m01*m13*m22 + m02*m11*m23 - m01*m12*m23;
161 tmp[1][0] = m13*m22*m30 - m12*m23*m30 - m13*m20*m32 + m10*m23*m32 + m12*m20*m33 - m10*m22*m33;
162 tmp[1][1] = m02*m23*m30 - m03*m22*m30 + m03*m20*m32 - m00*m23*m32 - m02*m20*m33 + m00*m22*m33;
163 tmp[1][2] = m03*m12*m30 - m02*m13*m30 - m03*m10*m32 + m00*m13*m32 + m02*m10*m33 - m00*m12*m33;
164 tmp[1][3] = m02*m13*m20 - m03*m12*m20 + m03*m10*m22 - m00*m13*m22 - m02*m10*m23 + m00*m12*m23;
165 tmp[2][0] = m11*m23*m30 - m13*m21*m30 + m13*m20*m31 - m10*m23*m31 - m11*m20*m33 + m10*m21*m33;
166 tmp[2][1] = m03*m21*m30 - m01*m23*m30 - m03*m20*m31 + m00*m23*m31 + m01*m20*m33 - m00*m21*m33;
167 tmp[2][2] = m01*m13*m30 - m03*m11*m30 + m03*m10*m31 - m00*m13*m31 - m01*m10*m33 + m00*m11*m33;
168 tmp[2][3] = m03*m11*m20 - m01*m13*m20 - m03*m10*m21 + m00*m13*m21 + m01*m10*m23 - m00*m11*m23;
169 tmp[3][0] = m12*m21*m30 - m11*m22*m30 - m12*m20*m31 + m10*m22*m31 + m11*m20*m32 - m10*m21*m32;
170 tmp[3][1] = m01*m22*m30 - m02*m21*m30 + m02*m20*m31 - m00*m22*m31 - m01*m20*m32 + m00*m21*m32;
171 tmp[3][2] = m02*m11*m30 - m01*m12*m30 - m02*m10*m31 + m00*m12*m31 + m01*m10*m32 - m00*m11*m32;
172 tmp[3][3] = m01*m12*m20 - m02*m11*m20 + m02*m10*m21 - m00*m12*m21 - m01*m10*m22 + m00*m11*m22;
173
174 double invDet = 1.0 / det;
175 for (int i = 0; i < 4; i++) {
176 for (int j = 0; j < 4; j++) {
177 inverse->fMat[i][j] = SkDoubleToMScalar(tmp[i][j] * invDet);
178 }
179 }
180 return true;
181}
182
183///////////////////////////////////////////////////////////////////////////////
184
185void SkMatrix44::map(const SkScalar src[4], SkScalar dst[4]) const {
186 SkScalar result[4];
187 for (int i = 0; i < 4; i++) {
188 SkMScalar value = 0;
189 for (int j = 0; j < 4; j++) {
190 value += fMat[j][i] * src[j];
191 }
192 result[i] = value;
193 }
194 memcpy(dst, result, sizeof(result));
195}
196
197///////////////////////////////////////////////////////////////////////////////
198
199void SkMatrix44::dump() const {
200 SkDebugf("[%g %g %g %g][%g %g %g %g][%g %g %g %g][%g %g %g %g]\n",
201 fMat[0][0], fMat[0][1], fMat[0][2], fMat[0][3],
202 fMat[1][0], fMat[1][1], fMat[1][2], fMat[1][3],
203 fMat[2][0], fMat[2][1], fMat[2][2], fMat[2][3],
204 fMat[3][0], fMat[3][1], fMat[3][2], fMat[3][3]);
205}
206
207
208