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