Home | History | Annotate | Download | only in utils
      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 
     13 SkMatrix44::SkMatrix44() {
     14     this->setIdentity();
     15 }
     16 
     17 SkMatrix44::SkMatrix44(const SkMatrix44& src) {
     18     memcpy(this, &src, sizeof(src));
     19 }
     20 
     21 SkMatrix44::SkMatrix44(const SkMatrix44& a, const SkMatrix44& b) {
     22     this->setConcat(a, b);
     23 }
     24 
     25 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 
     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 
     39 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 
     50 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 
     61 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 
     73 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 
     87 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 
     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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    225 static inline SkMScalar det2x2(double m00, double m01, double m10, double m11) {
    226     return SkDoubleToMScalar(m00 * m11 - m10 * m01);
    227 }
    228 
    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  */
    241 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 
    261 static inline double dabs(double x) {
    262     if (x < 0) {
    263         x = -x;
    264     }
    265     return x;
    266 }
    267 
    268 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 
    326 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 
    340 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 
    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 
    371 SkMatrix44::SkMatrix44(const SkMatrix& src) {
    372     initFromMatrix(fMat, src);
    373 }
    374 
    375 SkMatrix44& SkMatrix44::operator=(const SkMatrix& src) {
    376     initFromMatrix(fMat, src);
    377     return *this;
    378 }
    379 
    380 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