blob: f3f98a5279e8c2ec8430d79fb40320d24e86392c [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
reed@google.comda9fac02011-06-13 14:46:52 +000046void SkMatrix44::asColMajorf(float dst[]) const {
47 const SkMScalar* src = &fMat[0][0];
48#ifdef SK_MSCALAR_IS_DOUBLE
49 for (int i = 0; i < 16; ++i) {
50 dst[i] = SkMScalarToFloat(src[i]);
51 }
52#else
53 memcpy(dst, src, 16 * sizeof(float));
54#endif
55}
56
57void SkMatrix44::asColMajord(double dst[]) const {
58 const SkMScalar* src = &fMat[0][0];
59#ifdef SK_MSCALAR_IS_DOUBLE
60 memcpy(dst, src, 16 * sizeof(double));
61#else
62 for (int i = 0; i < 16; ++i) {
63 dst[i] = SkMScalarToDouble(src[i]);
64 }
65#endif
66}
67
68void SkMatrix44::asRowMajorf(float dst[]) const {
69 const SkMScalar* src = &fMat[0][0];
70 for (int i = 0; i < 4; ++i) {
71 dst[0] = SkMScalarToFloat(src[0]);
72 dst[4] = SkMScalarToFloat(src[1]);
73 dst[8] = SkMScalarToFloat(src[2]);
74 dst[12] = SkMScalarToFloat(src[3]);
75 src += 4;
76 dst += 1;
77 }
78}
79
80void SkMatrix44::asRowMajord(double dst[]) const {
81 const SkMScalar* src = &fMat[0][0];
82 for (int i = 0; i < 4; ++i) {
83 dst[0] = SkMScalarToDouble(src[0]);
84 dst[4] = SkMScalarToDouble(src[1]);
85 dst[8] = SkMScalarToDouble(src[2]);
86 dst[12] = SkMScalarToDouble(src[3]);
87 src += 4;
88 dst += 1;
89 }
90}
91
92///////////////////////////////////////////////////////////////////////////////
93
reed@google.com8260a892011-06-13 14:02:52 +000094static const SkMatrix44 gIdentity44;
95
96bool SkMatrix44::isIdentity() const {
97 return *this == gIdentity44;
98}
99
100///////////////////////////////////////////////////////////////////////////////
101
102void SkMatrix44::setIdentity() {
103 sk_bzero(fMat, sizeof(fMat));
104 fMat[0][0] = fMat[1][1] = fMat[2][2] = fMat[3][3] = 1;
105}
106
107void SkMatrix44::set3x3(SkMScalar m00, SkMScalar m01, SkMScalar m02,
108 SkMScalar m10, SkMScalar m11, SkMScalar m12,
109 SkMScalar m20, SkMScalar m21, SkMScalar m22) {
110 sk_bzero(fMat, sizeof(fMat));
111 fMat[0][0] = m00; fMat[0][1] = m01; fMat[0][2] = m02; fMat[0][3] = 0;
112 fMat[1][0] = m10; fMat[1][1] = m11; fMat[1][2] = m12; fMat[1][3] = 0;
113 fMat[2][0] = m20; fMat[2][1] = m21; fMat[2][2] = m22; fMat[2][3] = 0;
114 fMat[3][0] = 0; fMat[3][1] = 0; fMat[3][2] = 0; fMat[3][3] = 1;
115}
116
117///////////////////////////////////////////////////////////////////////////////
118
119void SkMatrix44::setTranslate(SkMScalar tx, SkMScalar ty, SkMScalar tz) {
120 this->setIdentity();
121 fMat[3][0] = tx;
122 fMat[3][1] = ty;
123 fMat[3][2] = tz;
124 fMat[3][3] = 1;
125}
126
127void SkMatrix44::preTranslate(SkMScalar dx, SkMScalar dy, SkMScalar dz) {
128 SkMatrix44 mat;
129 mat.setTranslate(dx, dy, dz);
130 this->preConcat(mat);
131}
132
133void SkMatrix44::postTranslate(SkMScalar dx, SkMScalar dy, SkMScalar dz) {
134 fMat[3][0] += dx;
135 fMat[3][1] += dy;
136 fMat[3][2] += dz;
137}
138
139///////////////////////////////////////////////////////////////////////////////
140
141void SkMatrix44::setScale(SkMScalar sx, SkMScalar sy, SkMScalar sz) {
142 sk_bzero(fMat, sizeof(fMat));
143 fMat[0][0] = sx;
144 fMat[1][1] = sy;
145 fMat[2][2] = sz;
146 fMat[3][3] = 1;
147}
148
149void SkMatrix44::preScale(SkMScalar sx, SkMScalar sy, SkMScalar sz) {
150 SkMatrix44 tmp;
151 tmp.setScale(sx, sy, sz);
152 this->preConcat(tmp);
153}
154
155void SkMatrix44::postScale(SkMScalar sx, SkMScalar sy, SkMScalar sz) {
156 for (int i = 0; i < 4; i++) {
157 fMat[i][0] *= sx;
158 fMat[i][1] *= sy;
159 fMat[i][2] *= sz;
160 }
161}
162
163///////////////////////////////////////////////////////////////////////////////
164
165void SkMatrix44::setRotateAbout(SkMScalar x, SkMScalar y, SkMScalar z,
166 SkMScalar radians) {
167 double len2 = x * x + y * y + z * z;
168 if (len2 != 1) {
169 if (len2 == 0) {
170 this->setIdentity();
171 return;
172 }
173 double scale = 1 / sqrt(len2);
174 x *= scale;
175 y *= scale;
176 z *= scale;
177 }
178 this->setRotateAboutUnit(x, y, z, radians);
179}
180
181void SkMatrix44::setRotateAboutUnit(SkMScalar x, SkMScalar y, SkMScalar z,
182 SkMScalar radians) {
183 double c = cos(radians);
184 double s = sin(radians);
185 double C = 1 - c;
186 double xs = x * s;
187 double ys = y * s;
188 double zs = z * s;
189 double xC = x * C;
190 double yC = y * C;
191 double zC = z * C;
192 double xyC = x * yC;
193 double yzC = y * zC;
194 double zxC = z * xC;
195
196 // if you're looking at wikipedia, remember that we're column major.
197 this->set3x3(x * xC + c, xyC + zs, zxC - ys,
198 xyC - zs, y * yC + c, yzC + xs,
199 zxC + ys, yzC - xs, z * zC + c);
200}
201
202///////////////////////////////////////////////////////////////////////////////
203
204void SkMatrix44::setConcat(const SkMatrix44& a, const SkMatrix44& b) {
205 SkMScalar result[4][4];
206 for (int i = 0; i < 4; i++) {
207 for (int j = 0; j < 4; j++) {
208 double value = 0;
209 for (int k = 0; k < 4; k++) {
210 value += SkMScalarToDouble(a.fMat[k][i]) * b.fMat[j][k];
211 }
212 result[j][i] = SkDoubleToMScalar(value);
213 }
214 }
215 memcpy(fMat, result, sizeof(result));
216}
217
218///////////////////////////////////////////////////////////////////////////////
219
220static inline SkMScalar det2x2(double m00, double m01, double m10, double m11) {
221 return m00 * m11 - m10 * m01;
222}
223
224static inline double det3x3(double m00, double m01, double m02,
225 double m10, double m11, double m12,
226 double m20, double m21, double m22) {
227 return m00 * det2x2(m11, m12, m21, m22) -
228 m10 * det2x2(m01, m02, m21, m22) +
229 m20 * det2x2(m01, m02, m11, m12);
230}
231
232/** We always perform the calculation in doubles, to avoid prematurely losing
233 precision along the way. This relies on the compiler automatically
234 promoting our SkMScalar values to double (if needed).
235 */
236double SkMatrix44::determinant() const {
237 return fMat[0][0] * det3x3(fMat[1][1], fMat[1][2], fMat[1][3],
238 fMat[2][1], fMat[2][2], fMat[2][3],
239 fMat[3][1], fMat[3][2], fMat[3][3]) -
240 fMat[1][0] * det3x3(fMat[0][1], fMat[0][2], fMat[0][3],
241 fMat[2][1], fMat[2][2], fMat[2][3],
242 fMat[3][1], fMat[3][2], fMat[3][3]) +
243 fMat[2][0] * det3x3(fMat[0][1], fMat[0][2], fMat[0][3],
244 fMat[1][1], fMat[1][2], fMat[1][3],
245 fMat[3][1], fMat[3][2], fMat[3][3]) -
246 fMat[3][0] * det3x3(fMat[0][1], fMat[0][2], fMat[0][3],
247 fMat[1][1], fMat[1][2], fMat[1][3],
248 fMat[2][1], fMat[2][2], fMat[2][3]);
249}
250
251///////////////////////////////////////////////////////////////////////////////
252
253// just picked a small value. not sure how to pick the "right" one
254#define TOO_SMALL_FOR_DETERMINANT (1.e-8)
255
256static inline double dabs(double x) {
257 if (x < 0) {
258 x = -x;
259 }
260 return x;
261}
262
263bool SkMatrix44::invert(SkMatrix44* inverse) const {
264 double det = this->determinant();
265 if (dabs(det) < TOO_SMALL_FOR_DETERMINANT) {
266 return false;
267 }
268 if (NULL == inverse) {
269 return true;
270 }
271
272 // we explicitly promote to doubles to keep the intermediate values in
273 // higher precision (assuming SkMScalar isn't already a double)
274 double m00 = fMat[0][0];
275 double m01 = fMat[0][1];
276 double m02 = fMat[0][2];
277 double m03 = fMat[0][3];
278 double m10 = fMat[1][0];
279 double m11 = fMat[1][1];
280 double m12 = fMat[1][2];
281 double m13 = fMat[1][3];
282 double m20 = fMat[2][0];
283 double m21 = fMat[2][1];
284 double m22 = fMat[2][2];
285 double m23 = fMat[2][3];
286 double m30 = fMat[3][0];
287 double m31 = fMat[3][1];
288 double m32 = fMat[3][2];
289 double m33 = fMat[3][3];
290
291 double tmp[4][4];
292
293 tmp[0][0] = m12*m23*m31 - m13*m22*m31 + m13*m21*m32 - m11*m23*m32 - m12*m21*m33 + m11*m22*m33;
294 tmp[0][1] = m03*m22*m31 - m02*m23*m31 - m03*m21*m32 + m01*m23*m32 + m02*m21*m33 - m01*m22*m33;
295 tmp[0][2] = m02*m13*m31 - m03*m12*m31 + m03*m11*m32 - m01*m13*m32 - m02*m11*m33 + m01*m12*m33;
296 tmp[0][3] = m03*m12*m21 - m02*m13*m21 - m03*m11*m22 + m01*m13*m22 + m02*m11*m23 - m01*m12*m23;
297 tmp[1][0] = m13*m22*m30 - m12*m23*m30 - m13*m20*m32 + m10*m23*m32 + m12*m20*m33 - m10*m22*m33;
298 tmp[1][1] = m02*m23*m30 - m03*m22*m30 + m03*m20*m32 - m00*m23*m32 - m02*m20*m33 + m00*m22*m33;
299 tmp[1][2] = m03*m12*m30 - m02*m13*m30 - m03*m10*m32 + m00*m13*m32 + m02*m10*m33 - m00*m12*m33;
300 tmp[1][3] = m02*m13*m20 - m03*m12*m20 + m03*m10*m22 - m00*m13*m22 - m02*m10*m23 + m00*m12*m23;
301 tmp[2][0] = m11*m23*m30 - m13*m21*m30 + m13*m20*m31 - m10*m23*m31 - m11*m20*m33 + m10*m21*m33;
302 tmp[2][1] = m03*m21*m30 - m01*m23*m30 - m03*m20*m31 + m00*m23*m31 + m01*m20*m33 - m00*m21*m33;
303 tmp[2][2] = m01*m13*m30 - m03*m11*m30 + m03*m10*m31 - m00*m13*m31 - m01*m10*m33 + m00*m11*m33;
304 tmp[2][3] = m03*m11*m20 - m01*m13*m20 - m03*m10*m21 + m00*m13*m21 + m01*m10*m23 - m00*m11*m23;
305 tmp[3][0] = m12*m21*m30 - m11*m22*m30 - m12*m20*m31 + m10*m22*m31 + m11*m20*m32 - m10*m21*m32;
306 tmp[3][1] = m01*m22*m30 - m02*m21*m30 + m02*m20*m31 - m00*m22*m31 - m01*m20*m32 + m00*m21*m32;
307 tmp[3][2] = m02*m11*m30 - m01*m12*m30 - m02*m10*m31 + m00*m12*m31 + m01*m10*m32 - m00*m11*m32;
308 tmp[3][3] = m01*m12*m20 - m02*m11*m20 + m02*m10*m21 - m00*m12*m21 - m01*m10*m22 + m00*m11*m22;
309
310 double invDet = 1.0 / det;
311 for (int i = 0; i < 4; i++) {
312 for (int j = 0; j < 4; j++) {
313 inverse->fMat[i][j] = SkDoubleToMScalar(tmp[i][j] * invDet);
314 }
315 }
316 return true;
317}
318
319///////////////////////////////////////////////////////////////////////////////
320
321void SkMatrix44::map(const SkScalar src[4], SkScalar dst[4]) const {
322 SkScalar result[4];
323 for (int i = 0; i < 4; i++) {
324 SkMScalar value = 0;
325 for (int j = 0; j < 4; j++) {
326 value += fMat[j][i] * src[j];
327 }
328 result[i] = value;
329 }
330 memcpy(dst, result, sizeof(result));
331}
332
333///////////////////////////////////////////////////////////////////////////////
334
335void SkMatrix44::dump() const {
tomhudson@google.com9ac4a892011-06-28 13:53:13 +0000336 static const char* format =
337 "[%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 +0000338#if 0
tomhudson@google.com9ac4a892011-06-28 13:53:13 +0000339 SkDebugf(format,
reed@google.com8260a892011-06-13 14:02:52 +0000340 fMat[0][0], fMat[1][0], fMat[2][0], fMat[3][0],
341 fMat[0][1], fMat[1][1], fMat[2][1], fMat[3][1],
342 fMat[0][2], fMat[1][2], fMat[2][2], fMat[3][2],
343 fMat[0][3], fMat[1][3], fMat[2][3], fMat[3][3]);
tomhudson@google.com9ac4a892011-06-28 13:53:13 +0000344#else
345 SkDebugf(format,
346 fMat[0][0], fMat[0][1], fMat[0][2], fMat[0][3],
347 fMat[1][0], fMat[1][1], fMat[1][2], fMat[1][3],
348 fMat[2][0], fMat[2][1], fMat[2][2], fMat[2][3],
349 fMat[3][0], fMat[3][1], fMat[3][2], fMat[3][3]);
reed@google.com8260a892011-06-13 14:02:52 +0000350#endif
351}
352
353///////////////////////////////////////////////////////////////////////////////
354
355static void initFromMatrix(SkMScalar dst[4][4], const SkMatrix& src) {
356 sk_bzero(dst, 16 * sizeof(SkMScalar));
357 dst[0][0] = src[SkMatrix::kMScaleX];
358 dst[1][0] = src[SkMatrix::kMSkewX];
359 dst[3][0] = src[SkMatrix::kMTransX];
360 dst[0][1] = src[SkMatrix::kMSkewY];
361 dst[1][1] = src[SkMatrix::kMScaleY];
362 dst[3][1] = src[SkMatrix::kMTransY];
363 dst[2][2] = dst[3][3] = 1;
364}
365
366SkMatrix44::SkMatrix44(const SkMatrix& src) {
367 initFromMatrix(fMat, src);
368}
369
370SkMatrix44& SkMatrix44::operator=(const SkMatrix& src) {
371 initFromMatrix(fMat, src);
372 return *this;
373}
374
375SkMatrix44::operator SkMatrix() const {
376 SkMatrix dst;
377 dst.reset(); // setup our perspective correctly for identity
378
379 dst[SkMatrix::kMScaleX] = SkMScalarToFloat(fMat[0][0]);
380 dst[SkMatrix::kMSkewX] = SkMScalarToFloat(fMat[1][0]);
381 dst[SkMatrix::kMTransX] = SkMScalarToFloat(fMat[3][0]);
382
383 dst[SkMatrix::kMSkewY] = SkMScalarToFloat(fMat[0][1]);
384 dst[SkMatrix::kMScaleY] = SkMScalarToFloat(fMat[1][1]);
385 dst[SkMatrix::kMTransY] = SkMScalarToFloat(fMat[3][1]);
386
387 return dst;
388}