• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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