blob: 803747fa4652d1c891f8c18bfff4d33a0c98b807 [file] [log] [blame]
reed@google.com8260a892011-06-13 14:02:52 +00001/*
2 Copyright 2011 Google Inc.
3
4 Licensed under the Apache License, Version 2.0 (the "License");
5 you may not use this file except in compliance with the License.
6 You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
15 */
16
17
18#include "SkMatrix44.h"
19
20SkMatrix44::SkMatrix44() {
21 this->setIdentity();
22}
23
24SkMatrix44::SkMatrix44(const SkMatrix44& src) {
25 memcpy(this, &src, sizeof(src));
26}
27
28SkMatrix44::SkMatrix44(const SkMatrix44& a, const SkMatrix44& b) {
29 this->setConcat(a, b);
30}
31
32SkMScalar SkMatrix44::get(int row, int col) const {
33 SkASSERT(row <= 3 && row >= 0);
34 SkASSERT(col <= 3 && col >= 0);
35 return fMat[col][row];
36}
37
38void SkMatrix44::set(int row, int col, const SkMScalar& value) {
39 SkASSERT(row <= 3 && row >= 0);
40 SkASSERT(col <= 3 && col >= 0);
41 fMat[col][row] = value;
42}
43
44///////////////////////////////////////////////////////////////////////////////
45
46static const SkMatrix44 gIdentity44;
47
48bool SkMatrix44::isIdentity() const {
49 return *this == gIdentity44;
50}
51
52///////////////////////////////////////////////////////////////////////////////
53
54void SkMatrix44::setIdentity() {
55 sk_bzero(fMat, sizeof(fMat));
56 fMat[0][0] = fMat[1][1] = fMat[2][2] = fMat[3][3] = 1;
57}
58
59void SkMatrix44::set3x3(SkMScalar m00, SkMScalar m01, SkMScalar m02,
60 SkMScalar m10, SkMScalar m11, SkMScalar m12,
61 SkMScalar m20, SkMScalar m21, SkMScalar m22) {
62 sk_bzero(fMat, sizeof(fMat));
63 fMat[0][0] = m00; fMat[0][1] = m01; fMat[0][2] = m02; fMat[0][3] = 0;
64 fMat[1][0] = m10; fMat[1][1] = m11; fMat[1][2] = m12; fMat[1][3] = 0;
65 fMat[2][0] = m20; fMat[2][1] = m21; fMat[2][2] = m22; fMat[2][3] = 0;
66 fMat[3][0] = 0; fMat[3][1] = 0; fMat[3][2] = 0; fMat[3][3] = 1;
67}
68
69///////////////////////////////////////////////////////////////////////////////
70
71void SkMatrix44::setTranslate(SkMScalar tx, SkMScalar ty, SkMScalar tz) {
72 this->setIdentity();
73 fMat[3][0] = tx;
74 fMat[3][1] = ty;
75 fMat[3][2] = tz;
76 fMat[3][3] = 1;
77}
78
79void SkMatrix44::preTranslate(SkMScalar dx, SkMScalar dy, SkMScalar dz) {
80 SkMatrix44 mat;
81 mat.setTranslate(dx, dy, dz);
82 this->preConcat(mat);
83}
84
85void SkMatrix44::postTranslate(SkMScalar dx, SkMScalar dy, SkMScalar dz) {
86 fMat[3][0] += dx;
87 fMat[3][1] += dy;
88 fMat[3][2] += dz;
89}
90
91///////////////////////////////////////////////////////////////////////////////
92
93void SkMatrix44::setScale(SkMScalar sx, SkMScalar sy, SkMScalar sz) {
94 sk_bzero(fMat, sizeof(fMat));
95 fMat[0][0] = sx;
96 fMat[1][1] = sy;
97 fMat[2][2] = sz;
98 fMat[3][3] = 1;
99}
100
101void SkMatrix44::preScale(SkMScalar sx, SkMScalar sy, SkMScalar sz) {
102 SkMatrix44 tmp;
103 tmp.setScale(sx, sy, sz);
104 this->preConcat(tmp);
105}
106
107void SkMatrix44::postScale(SkMScalar sx, SkMScalar sy, SkMScalar sz) {
108 for (int i = 0; i < 4; i++) {
109 fMat[i][0] *= sx;
110 fMat[i][1] *= sy;
111 fMat[i][2] *= sz;
112 }
113}
114
115///////////////////////////////////////////////////////////////////////////////
116
117void SkMatrix44::setRotateAbout(SkMScalar x, SkMScalar y, SkMScalar z,
118 SkMScalar radians) {
119 double len2 = x * x + y * y + z * z;
120 if (len2 != 1) {
121 if (len2 == 0) {
122 this->setIdentity();
123 return;
124 }
125 double scale = 1 / sqrt(len2);
126 x *= scale;
127 y *= scale;
128 z *= scale;
129 }
130 this->setRotateAboutUnit(x, y, z, radians);
131}
132
133void SkMatrix44::setRotateAboutUnit(SkMScalar x, SkMScalar y, SkMScalar z,
134 SkMScalar radians) {
135 double c = cos(radians);
136 double s = sin(radians);
137 double C = 1 - c;
138 double xs = x * s;
139 double ys = y * s;
140 double zs = z * s;
141 double xC = x * C;
142 double yC = y * C;
143 double zC = z * C;
144 double xyC = x * yC;
145 double yzC = y * zC;
146 double zxC = z * xC;
147
148 // if you're looking at wikipedia, remember that we're column major.
149 this->set3x3(x * xC + c, xyC + zs, zxC - ys,
150 xyC - zs, y * yC + c, yzC + xs,
151 zxC + ys, yzC - xs, z * zC + c);
152}
153
154///////////////////////////////////////////////////////////////////////////////
155
156void SkMatrix44::setConcat(const SkMatrix44& a, const SkMatrix44& b) {
157 SkMScalar result[4][4];
158 for (int i = 0; i < 4; i++) {
159 for (int j = 0; j < 4; j++) {
160 double value = 0;
161 for (int k = 0; k < 4; k++) {
162 value += SkMScalarToDouble(a.fMat[k][i]) * b.fMat[j][k];
163 }
164 result[j][i] = SkDoubleToMScalar(value);
165 }
166 }
167 memcpy(fMat, result, sizeof(result));
168}
169
170///////////////////////////////////////////////////////////////////////////////
171
172static inline SkMScalar det2x2(double m00, double m01, double m10, double m11) {
173 return m00 * m11 - m10 * m01;
174}
175
176static inline double det3x3(double m00, double m01, double m02,
177 double m10, double m11, double m12,
178 double m20, double m21, double m22) {
179 return m00 * det2x2(m11, m12, m21, m22) -
180 m10 * det2x2(m01, m02, m21, m22) +
181 m20 * det2x2(m01, m02, m11, m12);
182}
183
184/** We always perform the calculation in doubles, to avoid prematurely losing
185 precision along the way. This relies on the compiler automatically
186 promoting our SkMScalar values to double (if needed).
187 */
188double SkMatrix44::determinant() const {
189 return fMat[0][0] * det3x3(fMat[1][1], fMat[1][2], fMat[1][3],
190 fMat[2][1], fMat[2][2], fMat[2][3],
191 fMat[3][1], fMat[3][2], fMat[3][3]) -
192 fMat[1][0] * det3x3(fMat[0][1], fMat[0][2], fMat[0][3],
193 fMat[2][1], fMat[2][2], fMat[2][3],
194 fMat[3][1], fMat[3][2], fMat[3][3]) +
195 fMat[2][0] * det3x3(fMat[0][1], fMat[0][2], fMat[0][3],
196 fMat[1][1], fMat[1][2], fMat[1][3],
197 fMat[3][1], fMat[3][2], fMat[3][3]) -
198 fMat[3][0] * det3x3(fMat[0][1], fMat[0][2], fMat[0][3],
199 fMat[1][1], fMat[1][2], fMat[1][3],
200 fMat[2][1], fMat[2][2], fMat[2][3]);
201}
202
203///////////////////////////////////////////////////////////////////////////////
204
205// just picked a small value. not sure how to pick the "right" one
206#define TOO_SMALL_FOR_DETERMINANT (1.e-8)
207
208static inline double dabs(double x) {
209 if (x < 0) {
210 x = -x;
211 }
212 return x;
213}
214
215bool SkMatrix44::invert(SkMatrix44* inverse) const {
216 double det = this->determinant();
217 if (dabs(det) < TOO_SMALL_FOR_DETERMINANT) {
218 return false;
219 }
220 if (NULL == inverse) {
221 return true;
222 }
223
224 // we explicitly promote to doubles to keep the intermediate values in
225 // higher precision (assuming SkMScalar isn't already a double)
226 double m00 = fMat[0][0];
227 double m01 = fMat[0][1];
228 double m02 = fMat[0][2];
229 double m03 = fMat[0][3];
230 double m10 = fMat[1][0];
231 double m11 = fMat[1][1];
232 double m12 = fMat[1][2];
233 double m13 = fMat[1][3];
234 double m20 = fMat[2][0];
235 double m21 = fMat[2][1];
236 double m22 = fMat[2][2];
237 double m23 = fMat[2][3];
238 double m30 = fMat[3][0];
239 double m31 = fMat[3][1];
240 double m32 = fMat[3][2];
241 double m33 = fMat[3][3];
242
243 double tmp[4][4];
244
245 tmp[0][0] = m12*m23*m31 - m13*m22*m31 + m13*m21*m32 - m11*m23*m32 - m12*m21*m33 + m11*m22*m33;
246 tmp[0][1] = m03*m22*m31 - m02*m23*m31 - m03*m21*m32 + m01*m23*m32 + m02*m21*m33 - m01*m22*m33;
247 tmp[0][2] = m02*m13*m31 - m03*m12*m31 + m03*m11*m32 - m01*m13*m32 - m02*m11*m33 + m01*m12*m33;
248 tmp[0][3] = m03*m12*m21 - m02*m13*m21 - m03*m11*m22 + m01*m13*m22 + m02*m11*m23 - m01*m12*m23;
249 tmp[1][0] = m13*m22*m30 - m12*m23*m30 - m13*m20*m32 + m10*m23*m32 + m12*m20*m33 - m10*m22*m33;
250 tmp[1][1] = m02*m23*m30 - m03*m22*m30 + m03*m20*m32 - m00*m23*m32 - m02*m20*m33 + m00*m22*m33;
251 tmp[1][2] = m03*m12*m30 - m02*m13*m30 - m03*m10*m32 + m00*m13*m32 + m02*m10*m33 - m00*m12*m33;
252 tmp[1][3] = m02*m13*m20 - m03*m12*m20 + m03*m10*m22 - m00*m13*m22 - m02*m10*m23 + m00*m12*m23;
253 tmp[2][0] = m11*m23*m30 - m13*m21*m30 + m13*m20*m31 - m10*m23*m31 - m11*m20*m33 + m10*m21*m33;
254 tmp[2][1] = m03*m21*m30 - m01*m23*m30 - m03*m20*m31 + m00*m23*m31 + m01*m20*m33 - m00*m21*m33;
255 tmp[2][2] = m01*m13*m30 - m03*m11*m30 + m03*m10*m31 - m00*m13*m31 - m01*m10*m33 + m00*m11*m33;
256 tmp[2][3] = m03*m11*m20 - m01*m13*m20 - m03*m10*m21 + m00*m13*m21 + m01*m10*m23 - m00*m11*m23;
257 tmp[3][0] = m12*m21*m30 - m11*m22*m30 - m12*m20*m31 + m10*m22*m31 + m11*m20*m32 - m10*m21*m32;
258 tmp[3][1] = m01*m22*m30 - m02*m21*m30 + m02*m20*m31 - m00*m22*m31 - m01*m20*m32 + m00*m21*m32;
259 tmp[3][2] = m02*m11*m30 - m01*m12*m30 - m02*m10*m31 + m00*m12*m31 + m01*m10*m32 - m00*m11*m32;
260 tmp[3][3] = m01*m12*m20 - m02*m11*m20 + m02*m10*m21 - m00*m12*m21 - m01*m10*m22 + m00*m11*m22;
261
262 double invDet = 1.0 / det;
263 for (int i = 0; i < 4; i++) {
264 for (int j = 0; j < 4; j++) {
265 inverse->fMat[i][j] = SkDoubleToMScalar(tmp[i][j] * invDet);
266 }
267 }
268 return true;
269}
270
271///////////////////////////////////////////////////////////////////////////////
272
273void SkMatrix44::map(const SkScalar src[4], SkScalar dst[4]) const {
274 SkScalar result[4];
275 for (int i = 0; i < 4; i++) {
276 SkMScalar value = 0;
277 for (int j = 0; j < 4; j++) {
278 value += fMat[j][i] * src[j];
279 }
280 result[i] = value;
281 }
282 memcpy(dst, result, sizeof(result));
283}
284
285///////////////////////////////////////////////////////////////////////////////
286
287void SkMatrix44::dump() const {
288 SkDebugf("[%g %g %g %g][%g %g %g %g][%g %g %g %g][%g %g %g %g]\n",
289#if 0
290 fMat[0][0], fMat[0][1], fMat[0][2], fMat[0][3],
291 fMat[1][0], fMat[1][1], fMat[1][2], fMat[1][3],
292 fMat[2][0], fMat[2][1], fMat[2][2], fMat[2][3],
293 fMat[3][0], fMat[3][1], fMat[3][2], fMat[3][3]);
294#else
295 fMat[0][0], fMat[1][0], fMat[2][0], fMat[3][0],
296 fMat[0][1], fMat[1][1], fMat[2][1], fMat[3][1],
297 fMat[0][2], fMat[1][2], fMat[2][2], fMat[3][2],
298 fMat[0][3], fMat[1][3], fMat[2][3], fMat[3][3]);
299#endif
300}
301
302///////////////////////////////////////////////////////////////////////////////
303
304static void initFromMatrix(SkMScalar dst[4][4], const SkMatrix& src) {
305 sk_bzero(dst, 16 * sizeof(SkMScalar));
306 dst[0][0] = src[SkMatrix::kMScaleX];
307 dst[1][0] = src[SkMatrix::kMSkewX];
308 dst[3][0] = src[SkMatrix::kMTransX];
309 dst[0][1] = src[SkMatrix::kMSkewY];
310 dst[1][1] = src[SkMatrix::kMScaleY];
311 dst[3][1] = src[SkMatrix::kMTransY];
312 dst[2][2] = dst[3][3] = 1;
313}
314
315SkMatrix44::SkMatrix44(const SkMatrix& src) {
316 initFromMatrix(fMat, src);
317}
318
319SkMatrix44& SkMatrix44::operator=(const SkMatrix& src) {
320 initFromMatrix(fMat, src);
321 return *this;
322}
323
324SkMatrix44::operator SkMatrix() const {
325 SkMatrix dst;
326 dst.reset(); // setup our perspective correctly for identity
327
328 dst[SkMatrix::kMScaleX] = SkMScalarToFloat(fMat[0][0]);
329 dst[SkMatrix::kMSkewX] = SkMScalarToFloat(fMat[1][0]);
330 dst[SkMatrix::kMTransX] = SkMScalarToFloat(fMat[3][0]);
331
332 dst[SkMatrix::kMSkewY] = SkMScalarToFloat(fMat[0][1]);
333 dst[SkMatrix::kMScaleY] = SkMScalarToFloat(fMat[1][1]);
334 dst[SkMatrix::kMTransY] = SkMScalarToFloat(fMat[3][1]);
335
336 return dst;
337}
338
339
340