Home | API | File List | Examples | Download

lib3ds_matrix.c

00001 /*
00002     Copyright (C) 1996-2008 by Jan Eric Kyprianidis <www.kyprianidis.com>
00003     All rights reserved.
00004     
00005     This program is free  software: you can redistribute it and/or modify 
00006     it under the terms of the GNU Lesser General Public License as published 
00007     by the Free Software Foundation, either version 2.1 of the License, or 
00008     (at your option) any later version.
00009 
00010     Thisprogram  is  distributed in the hope that it will be useful, 
00011     but WITHOUT ANY WARRANTY; without even the implied warranty of 
00012     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 
00013     GNU Lesser General Public License for more details.
00014     
00015     You should  have received a copy of the GNU Lesser General Public License
00016     along with  this program; If not, see <http://www.gnu.org/licenses/>. 
00017 */
00018 
00022 #include "lib3ds_impl.h"
00023 
00024 
00030 void
00031 lib3ds_matrix_zero(float m[4][4]) {
00032     int i, j;
00033 
00034     for (i = 0; i < 4; i++) {
00035         for (j = 0; j < 4; j++) m[i][j] = 0.0f;
00036     }
00037 }
00038 
00039 
00045 void
00046 lib3ds_matrix_identity(float m[4][4]) {
00047     int i, j;
00048 
00049     for (i = 0; i < 4; i++) {
00050         for (j = 0; j < 4; j++) m[i][j] = 0.0;
00051     }
00052     for (i = 0; i < 4; i++) m[i][i] = 1.0;
00053 }
00054 
00055 
00059 void
00060 lib3ds_matrix_copy(float dest[4][4], float src[4][4]) {
00061     memcpy(dest, src, 16 * sizeof(float));
00062 }
00063 
00064 
00068 void
00069 lib3ds_matrix_neg(float m[4][4]) {
00070     int i, j;
00071 
00072     for (j = 0; j < 4; j++) {
00073         for (i = 0; i < 4; i++) {
00074             m[j][i] = -m[j][i];
00075         }
00076     }
00077 }
00078 
00079 
00083 void
00084 lib3ds_matrix_transpose(float m[4][4]) {
00085     int i, j;
00086     float swp;
00087 
00088     for (j = 0; j < 4; j++) {
00089         for (i = j + 1; i < 4; i++) {
00090             swp = m[j][i];
00091             m[j][i] = m[i][j];
00092             m[i][j] = swp;
00093         }
00094     }
00095 }
00096 
00097 
00101 void
00102 lib3ds_matrix_add(float m[4][4], float a[4][4], float b[4][4]) {
00103     int i, j;
00104 
00105     for (j = 0; j < 4; j++) {
00106         for (i = 0; i < 4; i++) {
00107             m[j][i] = a[j][i] + b[j][i];
00108         }
00109     }
00110 }
00111 
00112 
00120 void
00121 lib3ds_matrix_sub(float m[4][4], float a[4][4], float b[4][4]) {
00122     int i, j;
00123 
00124     for (j = 0; j < 4; j++) {
00125         for (i = 0; i < 4; i++) {
00126             m[j][i] = a[j][i] - b[j][i];
00127         }
00128     }
00129 }
00130 
00131 
00135 void
00136 lib3ds_matrix_mult(float m[4][4], float a[4][4], float b[4][4]) {
00137     float tmp[4][4];
00138     int i, j, k;
00139     float ab;
00140 
00141     memcpy(tmp, a, 16 * sizeof(float));
00142     for (j = 0; j < 4; j++) {
00143         for (i = 0; i < 4; i++) {
00144             ab = 0.0f;
00145             for (k = 0; k < 4; k++) ab += tmp[k][i] * b[j][k];
00146             m[j][i] = ab;
00147         }
00148     }
00149 }
00150 
00151 
00158 void
00159 lib3ds_matrix_scalar(float m[4][4], float k) {
00160     int i, j;
00161 
00162     for (j = 0; j < 4; j++) {
00163         for (i = 0; i < 4; i++) {
00164             m[j][i] *= k;
00165         }
00166     }
00167 }
00168 
00169 
00170 static float
00171 det2x2(
00172     float a, float b,
00173     float c, float d) {
00174     return((a)*(d) - (b)*(c));
00175 }
00176 
00177 
00178 static float
00179 det3x3(
00180     float a1, float a2, float a3,
00181     float b1, float b2, float b3,
00182     float c1, float c2, float c3) {
00183     return(
00184               a1*det2x2(b2, b3, c2, c3) -
00185               b1*det2x2(a2, a3, c2, c3) +
00186               c1*det2x2(a2, a3, b2, b3)
00187           );
00188 }
00189 
00190 
00194 float
00195 lib3ds_matrix_det(float m[4][4]) {
00196     float a1, a2, a3, a4, b1, b2, b3, b4, c1, c2, c3, c4, d1, d2, d3, d4;
00197 
00198     a1 = m[0][0];
00199     b1 = m[1][0];
00200     c1 = m[2][0];
00201     d1 = m[3][0];
00202     a2 = m[0][1];
00203     b2 = m[1][1];
00204     c2 = m[2][1];
00205     d2 = m[3][1];
00206     a3 = m[0][2];
00207     b3 = m[1][2];
00208     c3 = m[2][2];
00209     d3 = m[3][2];
00210     a4 = m[0][3];
00211     b4 = m[1][3];
00212     c4 = m[2][3];
00213     d4 = m[3][3];
00214     return(
00215               a1 * det3x3(b2, b3, b4, c2, c3, c4, d2, d3, d4) -
00216               b1 * det3x3(a2, a3, a4, c2, c3, c4, d2, d3, d4) +
00217               c1 * det3x3(a2, a3, a4, b2, b3, b4, d2, d3, d4) -
00218               d1 * det3x3(a2, a3, a4, b2, b3, b4, c2, c3, c4)
00219           );
00220 }
00221 
00222 
00232 int
00233 lib3ds_matrix_inv(float m[4][4]) {
00234     int i, j, k;
00235     int pvt_i[4], pvt_j[4];            /* Locations of pivot elements */
00236     float pvt_val;               /* Value of current pivot element */
00237     float hold;                  /* Temporary storage */
00238     float determinat;
00239 
00240     determinat = 1.0f;
00241     for (k = 0; k < 4; k++)  {
00242         /* Locate k'th pivot element */
00243         pvt_val = m[k][k];          /* Initialize for search */
00244         pvt_i[k] = k;
00245         pvt_j[k] = k;
00246         for (i = k; i < 4; i++) {
00247             for (j = k; j < 4; j++) {
00248                 if (fabs(m[i][j]) > fabs(pvt_val)) {
00249                     pvt_i[k] = i;
00250                     pvt_j[k] = j;
00251                     pvt_val = m[i][j];
00252                 }
00253             }
00254         }
00255 
00256         /* Product of pivots, gives determinant when finished */
00257         determinat *= pvt_val;
00258         if (fabs(determinat) < LIB3DS_EPSILON) {
00259             return(FALSE);  /* Matrix is singular (zero determinant) */
00260         }
00261 
00262         /* "Interchange" rows (with sign change stuff) */
00263         i = pvt_i[k];
00264         if (i != k) {             /* If rows are different */
00265             for (j = 0; j < 4; j++) {
00266                 hold = -m[k][j];
00267                 m[k][j] = m[i][j];
00268                 m[i][j] = hold;
00269             }
00270         }
00271 
00272         /* "Interchange" columns */
00273         j = pvt_j[k];
00274         if (j != k) {            /* If columns are different */
00275             for (i = 0; i < 4; i++) {
00276                 hold = -m[i][k];
00277                 m[i][k] = m[i][j];
00278                 m[i][j] = hold;
00279             }
00280         }
00281 
00282         /* Divide column by minus pivot value */
00283         for (i = 0; i < 4; i++) {
00284             if (i != k) m[i][k] /= (-pvt_val) ;
00285         }
00286 
00287         /* Reduce the matrix */
00288         for (i = 0; i < 4; i++) {
00289             hold = m[i][k];
00290             for (j = 0; j < 4; j++) {
00291                 if (i != k && j != k) m[i][j] += hold * m[k][j];
00292             }
00293         }
00294 
00295         /* Divide row by pivot */
00296         for (j = 0; j < 4; j++) {
00297             if (j != k) m[k][j] /= pvt_val;
00298         }
00299 
00300         /* Replace pivot by reciprocal (at last we can touch it). */
00301         m[k][k] = 1.0f / pvt_val;
00302     }
00303 
00304     /* That was most of the work, one final pass of row/column interchange */
00305     /* to finish */
00306     for (k = 4 - 2; k >= 0; k--) { /* Don't need to work with 1 by 1 corner*/
00307         i = pvt_j[k];          /* Rows to swap correspond to pivot COLUMN */
00308         if (i != k) {          /* If rows are different */
00309             for (j = 0; j < 4; j++) {
00310                 hold = m[k][j];
00311                 m[k][j] = -m[i][j];
00312                 m[i][j] = hold;
00313             }
00314         }
00315 
00316         j = pvt_i[k];         /* Columns to swap correspond to pivot ROW */
00317         if (j != k)           /* If columns are different */
00318             for (i = 0; i < 4; i++) {
00319                 hold = m[i][k];
00320                 m[i][k] = -m[i][j];
00321                 m[i][j] = hold;
00322             }
00323     }
00324     return(TRUE);
00325 }
00326 
00327 
00331 void
00332 lib3ds_matrix_translate(float m[4][4], float x, float y, float z) {
00333     int i;
00334 
00335     for (i = 0; i < 3; i++) {
00336         m[3][i] += m[0][i] * x + m[1][i] * y + m[2][i] * z;
00337     }
00338 }
00339 
00340 
00344 void
00345 lib3ds_matrix_scale(float m[4][4], float x, float y, float z) {
00346     int i;
00347 
00348     for (i = 0; i < 4; i++) {
00349         m[0][i] *= x;
00350         m[1][i] *= y;
00351         m[2][i] *= z;
00352     }
00353 }
00354 
00355 
00359 void
00360 lib3ds_matrix_rotate_quat(float m[4][4], float q[4]) {
00361     float s, xs, ys, zs, wx, wy, wz, xx, xy, xz, yy, yz, zz, l;
00362     float R[4][4];
00363 
00364     l = q[0] * q[0] + q[1] * q[1] + q[2] * q[2] + q[3] * q[3];
00365     if (fabs(l) < LIB3DS_EPSILON) {
00366         s = 1.0f;
00367     } else {
00368         s = 2.0f / l;
00369     }
00370 
00371     xs = q[0] * s;
00372     ys = q[1] * s;
00373     zs = q[2] * s;
00374     wx = q[3] * xs;
00375     wy = q[3] * ys;
00376     wz = q[3] * zs;
00377     xx = q[0] * xs;
00378     xy = q[0] * ys;
00379     xz = q[0] * zs;
00380     yy = q[1] * ys;
00381     yz = q[1] * zs;
00382     zz = q[2] * zs;
00383 
00384     R[0][0] = 1.0f - (yy + zz);
00385     R[1][0] = xy - wz;
00386     R[2][0] = xz + wy;
00387     R[0][1] = xy + wz;
00388     R[1][1] = 1.0f - (xx + zz);
00389     R[2][1] = yz - wx;
00390     R[0][2] = xz - wy;
00391     R[1][2] = yz + wx;
00392     R[2][2] = 1.0f - (xx + yy);
00393     R[3][0] = R[3][1] = R[3][2] = R[0][3] = R[1][3] = R[2][3] = 0.0f;
00394     R[3][3] = 1.0f;
00395 
00396     lib3ds_matrix_mult(m, m, R);
00397 }
00398 
00399 
00403 void
00404 lib3ds_matrix_rotate(float m[4][4], float angle, float ax, float ay, float az) {
00405     float q[4];
00406     float axis[3];
00407 
00408     lib3ds_vector_make(axis, ax, ay, az);
00409     lib3ds_quat_axis_angle(q, axis, angle);
00410     lib3ds_matrix_rotate_quat(m, q);
00411 }
00412 
00413 
00426 void
00427 lib3ds_matrix_camera(float matrix[4][4], float pos[3], float tgt[3], float roll) {
00428     float M[4][4];
00429     float x[3], y[3], z[3];
00430 
00431     lib3ds_vector_sub(y, tgt, pos);
00432     lib3ds_vector_normalize(y);
00433 
00434     if (y[0] != 0. || y[1] != 0) {
00435         z[0] = 0;
00436         z[1] = 0;
00437         z[2] = 1.0;
00438     } else { /* Special case:  looking straight up or down z axis */
00439         z[0] = -1.0;
00440         z[1] = 0;
00441         z[2] = 0;
00442     }
00443 
00444     lib3ds_vector_cross(x, y, z);
00445     lib3ds_vector_cross(z, x, y);
00446     lib3ds_vector_normalize(x);
00447     lib3ds_vector_normalize(z);
00448 
00449     lib3ds_matrix_identity(M);
00450     M[0][0] = x[0];
00451     M[1][0] = x[1];
00452     M[2][0] = x[2];
00453     M[0][1] = y[0];
00454     M[1][1] = y[1];
00455     M[2][1] = y[2];
00456     M[0][2] = z[0];
00457     M[1][2] = z[1];
00458     M[2][2] = z[2];
00459 
00460     lib3ds_matrix_identity(matrix);
00461     lib3ds_matrix_rotate(matrix, roll, 0, 1, 0);
00462     lib3ds_matrix_mult(matrix, matrix, M);
00463     lib3ds_matrix_translate(matrix, -pos[0], -pos[1], -pos[2]);
00464 }
00465 
00466 
00467 
00468 
00469 
00470