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