📄 m_matrix.c
字号:
return GL_TRUE;}/** * Compute inverse of a 3d transformation matrix. * * \param mat pointer to a GLmatrix structure. The matrix inverse will be * stored in the GLmatrix::inv attribute. * * \return GL_TRUE for success, GL_FALSE for failure (\p singular matrix). * * If the matrix is not an angle preserving matrix then calls * invert_matrix_3d_general for the actual calculation. Otherwise calculates * the inverse matrix analyzing and inverting each of the scaling, rotation and * translation parts. */static GLboolean invert_matrix_3d( GLmatrix *mat ){ const GLfloat *in = mat->m; GLfloat *out = mat->inv; if (!TEST_MAT_FLAGS(mat, MAT_FLAGS_ANGLE_PRESERVING)) { return invert_matrix_3d_general( mat ); } if (mat->flags & MAT_FLAG_UNIFORM_SCALE) { GLfloat scale = (MAT(in,0,0) * MAT(in,0,0) + MAT(in,0,1) * MAT(in,0,1) + MAT(in,0,2) * MAT(in,0,2)); if (scale == 0.0) return GL_FALSE; scale = 1.0F / scale; /* Transpose and scale the 3 by 3 upper-left submatrix. */ MAT(out,0,0) = scale * MAT(in,0,0); MAT(out,1,0) = scale * MAT(in,0,1); MAT(out,2,0) = scale * MAT(in,0,2); MAT(out,0,1) = scale * MAT(in,1,0); MAT(out,1,1) = scale * MAT(in,1,1); MAT(out,2,1) = scale * MAT(in,1,2); MAT(out,0,2) = scale * MAT(in,2,0); MAT(out,1,2) = scale * MAT(in,2,1); MAT(out,2,2) = scale * MAT(in,2,2); } else if (mat->flags & MAT_FLAG_ROTATION) { /* Transpose the 3 by 3 upper-left submatrix. */ MAT(out,0,0) = MAT(in,0,0); MAT(out,1,0) = MAT(in,0,1); MAT(out,2,0) = MAT(in,0,2); MAT(out,0,1) = MAT(in,1,0); MAT(out,1,1) = MAT(in,1,1); MAT(out,2,1) = MAT(in,1,2); MAT(out,0,2) = MAT(in,2,0); MAT(out,1,2) = MAT(in,2,1); MAT(out,2,2) = MAT(in,2,2); } else { /* pure translation */ MEMCPY( out, Identity, sizeof(Identity) ); MAT(out,0,3) = - MAT(in,0,3); MAT(out,1,3) = - MAT(in,1,3); MAT(out,2,3) = - MAT(in,2,3); return GL_TRUE; } if (mat->flags & MAT_FLAG_TRANSLATION) { /* Do the translation part */ MAT(out,0,3) = - (MAT(in,0,3) * MAT(out,0,0) + MAT(in,1,3) * MAT(out,0,1) + MAT(in,2,3) * MAT(out,0,2) ); MAT(out,1,3) = - (MAT(in,0,3) * MAT(out,1,0) + MAT(in,1,3) * MAT(out,1,1) + MAT(in,2,3) * MAT(out,1,2) ); MAT(out,2,3) = - (MAT(in,0,3) * MAT(out,2,0) + MAT(in,1,3) * MAT(out,2,1) + MAT(in,2,3) * MAT(out,2,2) ); } else { MAT(out,0,3) = MAT(out,1,3) = MAT(out,2,3) = 0.0; } return GL_TRUE;}/** * Compute inverse of an identity transformation matrix. * * \param mat pointer to a GLmatrix structure. The matrix inverse will be * stored in the GLmatrix::inv attribute. * * \return always GL_TRUE. * * Simply copies Identity into GLmatrix::inv. */static GLboolean invert_matrix_identity( GLmatrix *mat ){ MEMCPY( mat->inv, Identity, sizeof(Identity) ); return GL_TRUE;}/** * Compute inverse of a no-rotation 3d transformation matrix. * * \param mat pointer to a GLmatrix structure. The matrix inverse will be * stored in the GLmatrix::inv attribute. * * \return GL_TRUE for success, GL_FALSE for failure (\p singular matrix). * * Calculates the */static GLboolean invert_matrix_3d_no_rot( GLmatrix *mat ){ const GLfloat *in = mat->m; GLfloat *out = mat->inv; if (MAT(in,0,0) == 0 || MAT(in,1,1) == 0 || MAT(in,2,2) == 0 ) return GL_FALSE; MEMCPY( out, Identity, 16 * sizeof(GLfloat) ); MAT(out,0,0) = 1.0F / MAT(in,0,0); MAT(out,1,1) = 1.0F / MAT(in,1,1); MAT(out,2,2) = 1.0F / MAT(in,2,2); if (mat->flags & MAT_FLAG_TRANSLATION) { MAT(out,0,3) = - (MAT(in,0,3) * MAT(out,0,0)); MAT(out,1,3) = - (MAT(in,1,3) * MAT(out,1,1)); MAT(out,2,3) = - (MAT(in,2,3) * MAT(out,2,2)); } return GL_TRUE;}/** * Compute inverse of a no-rotation 2d transformation matrix. * * \param mat pointer to a GLmatrix structure. The matrix inverse will be * stored in the GLmatrix::inv attribute. * * \return GL_TRUE for success, GL_FALSE for failure (\p singular matrix). * * Calculates the inverse matrix by applying the inverse scaling and * translation to the identity matrix. */static GLboolean invert_matrix_2d_no_rot( GLmatrix *mat ){ const GLfloat *in = mat->m; GLfloat *out = mat->inv; if (MAT(in,0,0) == 0 || MAT(in,1,1) == 0) return GL_FALSE; MEMCPY( out, Identity, 16 * sizeof(GLfloat) ); MAT(out,0,0) = 1.0F / MAT(in,0,0); MAT(out,1,1) = 1.0F / MAT(in,1,1); if (mat->flags & MAT_FLAG_TRANSLATION) { MAT(out,0,3) = - (MAT(in,0,3) * MAT(out,0,0)); MAT(out,1,3) = - (MAT(in,1,3) * MAT(out,1,1)); } return GL_TRUE;}#if 0/* broken */static GLboolean invert_matrix_perspective( GLmatrix *mat ){ const GLfloat *in = mat->m; GLfloat *out = mat->inv; if (MAT(in,2,3) == 0) return GL_FALSE; MEMCPY( out, Identity, 16 * sizeof(GLfloat) ); MAT(out,0,0) = 1.0F / MAT(in,0,0); MAT(out,1,1) = 1.0F / MAT(in,1,1); MAT(out,0,3) = MAT(in,0,2); MAT(out,1,3) = MAT(in,1,2); MAT(out,2,2) = 0; MAT(out,2,3) = -1; MAT(out,3,2) = 1.0F / MAT(in,2,3); MAT(out,3,3) = MAT(in,2,2) * MAT(out,3,2); return GL_TRUE;}#endif/** * Matrix inversion function pointer type. */typedef GLboolean (*inv_mat_func)( GLmatrix *mat );/** * Table of the matrix inversion functions according to the matrix type. */static inv_mat_func inv_mat_tab[7] = { invert_matrix_general, invert_matrix_identity, invert_matrix_3d_no_rot,#if 0 /* Don't use this function for now - it fails when the projection matrix * is premultiplied by a translation (ala Chromium's tilesort SPU). */ invert_matrix_perspective,#else invert_matrix_general,#endif invert_matrix_3d, /* lazy! */ invert_matrix_2d_no_rot, invert_matrix_3d};/** * Compute inverse of a transformation matrix. * * \param mat pointer to a GLmatrix structure. The matrix inverse will be * stored in the GLmatrix::inv attribute. * * \return GL_TRUE for success, GL_FALSE for failure (\p singular matrix). * * Calls the matrix inversion function in inv_mat_tab corresponding to the * given matrix type. In case of failure, updates the MAT_FLAG_SINGULAR flag, * and copies the identity matrix into GLmatrix::inv. */static GLboolean matrix_invert( GLmatrix *mat ){ if (inv_mat_tab[mat->type](mat)) { mat->flags &= ~MAT_FLAG_SINGULAR; return GL_TRUE; } else { mat->flags |= MAT_FLAG_SINGULAR; MEMCPY( mat->inv, Identity, sizeof(Identity) ); return GL_FALSE; }}/*@}*//**********************************************************************//** \name Matrix generation *//*@{*//** * Generate a 4x4 transformation matrix from glRotate parameters, and * post-multiply the input matrix by it. * * \author * This function was contributed by Erich Boleyn (erich@uruk.org). * Optimizations contributed by Rudolf Opalla (rudi@khm.de). */void_math_matrix_rotate( GLmatrix *mat, GLfloat angle, GLfloat x, GLfloat y, GLfloat z ){ GLfloat xx, yy, zz, xy, yz, zx, xs, ys, zs, one_c, s, c; GLfloat m[16]; GLboolean optimized; s = (GLfloat) _mesa_sin( angle * DEG2RAD ); c = (GLfloat) _mesa_cos( angle * DEG2RAD ); MEMCPY(m, Identity, sizeof(GLfloat)*16); optimized = GL_FALSE;#define M(row,col) m[col*4+row] if (x == 0.0F) { if (y == 0.0F) { if (z != 0.0F) { optimized = GL_TRUE; /* rotate only around z-axis */ M(0,0) = c; M(1,1) = c; if (z < 0.0F) { M(0,1) = s; M(1,0) = -s; } else { M(0,1) = -s; M(1,0) = s; } } } else if (z == 0.0F) { optimized = GL_TRUE; /* rotate only around y-axis */ M(0,0) = c; M(2,2) = c; if (y < 0.0F) { M(0,2) = -s; M(2,0) = s; } else { M(0,2) = s; M(2,0) = -s; } } } else if (y == 0.0F) { if (z == 0.0F) { optimized = GL_TRUE; /* rotate only around x-axis */ M(1,1) = c; M(2,2) = c; if (x < 0.0F) { M(1,2) = s; M(2,1) = -s; } else { M(1,2) = -s; M(2,1) = s; } } } if (!optimized) { const GLfloat mag = SQRTF(x * x + y * y + z * z); if (mag <= 1.0e-4) { /* no rotation, leave mat as-is */ return; } x /= mag; y /= mag; z /= mag; /* * Arbitrary axis rotation matrix. * * This is composed of 5 matrices, Rz, Ry, T, Ry', Rz', multiplied * like so: Rz * Ry * T * Ry' * Rz'. T is the final rotation * (which is about the X-axis), and the two composite transforms * Ry' * Rz' and Rz * Ry are (respectively) the rotations necessary * from the arbitrary axis to the X-axis then back. They are * all elementary rotations. * * Rz' is a rotation about the Z-axis, to bring the axis vector * into the x-z plane. Then Ry' is applied, rotating about the * Y-axis to bring the axis vector parallel with the X-axis. The * rotation about the X-axis is then performed. Ry and Rz are * simply the respective inverse transforms to bring the arbitrary * axis back to it's original orientation. The first transforms * Rz' and Ry' are considered inverses, since the data from the * arbitrary axis gives you info on how to get to it, not how * to get away from it, and an inverse must be applied. * * The basic calculation used is to recognize that the arbitrary * axis vector (x, y, z), since it is of unit length, actually * represents the sines and cosines of the angles to rotate the * X-axis to the same orientation, with theta being the angle about * Z and phi the angle about Y (in the order described above) * as follows: * * cos ( theta ) = x / sqrt ( 1 - z^2 ) * sin ( theta ) = y / sqrt ( 1 - z^2 ) * * cos ( phi ) = sqrt ( 1 - z^2 ) * sin ( phi ) = z * * Note that cos ( phi ) can further be inserted to the above * formulas: * * cos ( theta ) = x / cos ( phi ) * sin ( theta ) = y / sin ( phi ) * * ...etc. Because of those relations and the standard trigonometric * relations, it is pssible to reduce the transforms down to what * is used below. It may be that any primary axis chosen will give the * same results (modulo a sign convention) using thie method. * * Particularly nice is to notice that all divisions that might * have caused trouble when parallel to certain planes or * axis go away with care paid to reducing the expressions. * After checking, it does perform correctly under all cases, since * in all the cases of division where the denominator would have * been zero, the numerator would have been zero as well, giving * the expected result. */ xx = x * x; yy = y * y; zz = z * z; xy = x * y; yz = y * z; zx = z * x; xs = x * s; ys = y * s; zs = z * s; one_c = 1.0F - c; /* We already hold the identity-matrix so we can skip some statements */ M(0,0) = (one_c * xx) + c; M(0,1) = (one_c * xy) - zs; M(0,2) = (one_c * zx) + ys;/* M(0,3) = 0.0F; */ M(1,0) = (one_c * xy) + zs; M(1,1) = (one_c * yy) + c; M(1,2) = (one_c * yz) - xs;/* M(1,3) = 0.0F; */ M(2,0) = (one_c * zx) - ys; M(2,1) = (one_c * yz) + xs; M(2,2) = (one_c * zz) + c;/* M(2,3) = 0.0F; *//* M(3,0) = 0.0F; M(3,1) = 0.0F; M(3,2) = 0.0F; M(3,3) = 1.0F;*/ }#undef M matrix_multf( mat, m, MAT_FLAG_ROTATION );}/** * Apply a perspective projection matrix. * * \param mat matrix to apply the projection. * \param left left clipping plane coordinate. * \param right right clipping plane coordinate. * \param bottom bottom clipping plane coordinate. * \param top top clipping plane coordinate. * \param nearval distance to the near clipping plane. * \param farval distance to the far clipping plane. * * Creates the projection matrix and multiplies it with \p mat, marking the * MAT_FLAG_PERSPECTIVE flag. */void_math_matrix_frustum( GLmatrix *mat, GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat nearval, GLfloat farval ){ GLfloat x, y, a, b, c, d; GLfloat m[16]; x = (2.0F*nearval) / (right-left); y = (2.0F*nearval) / (top-bottom); a = (right+left) / (right-left); b = (top+bottom) / (top-bottom); c = -(farval+nearval) / ( farval-nearval); d = -(2.0F*farval*nearval) / (farval-nearval); /* error? */#define M(row,col) m[col*4+row] M(0,0) = x; M(0,1) = 0.0F; M(0,2) = a; M(0,3) = 0.0F; M(1,0) = 0.0F; M(1,1) = y; M(1,2) = b; M(1,3) = 0.0F; M(2,0) = 0.0F; M(2,1) = 0.0F; M(2,2) = c; M(2,3) = d; M(3,0) = 0.0F; M(3,1) = 0.0F; M(3,2) = -1.0F; M(3,3) = 0.0F;#undef M matrix_multf( mat, m, MAT_FLAG_PERSPECTIVE );}/** * Apply an orthographic projection matrix. * * \param mat matrix to apply the projection. * \param left left clipping plane coordinate. * \param right right clipping plane coordinate. * \param bottom bottom clipping plane coordinate. * \param top top clipping plane coordinate. * \param nearval distance to the near clipping plane. * \param farval distance to the far clipping plane. * * Creates the projection matrix and multiplies it with \p mat, marking the * MAT_FLAG_GENERAL_SCALE and MAT_FLAG_TRANSLATION flags. */void_math_matrix_ortho( GLmatrix *mat, GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat nearval, GLfloat farval ){ GLfloat m[16];#define M(row,col) m[col*4+row] M(0,0) = 2.0F / (right-left); M(0,1) = 0.0F; M(0,2) = 0.0F; M(0,3) = -(right+left) / (right-left); M(1,0) = 0.0F; M(1,1) = 2.0F / (top-bottom); M(1,2) = 0.0F; M(1,3) = -(top+bottom) / (top-bottom); M(2,0) = 0.0F; M(2,1) = 0.0F; M(2,2) = -2.0F / (farval-nearval); M(2,3) = -(farval+nearval) / (farval-nearval); M(3,0) = 0.0F; M(3,1) = 0.0F; M(3,2) = 0.0F; M(3,3) = 1.0F;#undef M matrix_multf( mat, m, (MAT_FLAG_GENERAL_SCALE|MAT_FLAG_TRANSLATION));}/** * Multiply a matrix with a general scaling matrix. * * \param mat matrix. * \param x x axis scale factor. * \param y y axis scale factor. * \param z z axis scale factor. * * Multiplies in-place the elements of \p mat by the scale factors. Checks if * the scales factors are roughly the same, marking the MAT_FLAG_UNIFORM_SCALE * flag, or MAT_FLAG_GENERAL_SCALE. Marks the MAT_DIRTY_TYPE and * MAT_DIRTY_INVERSE dirty flags. */void_math_matrix_scale( GLmatrix *mat, GLfloat x, GLfloat y, GLfloat z ){ GLfloat *m = mat->m; m[0] *= x; m[4] *= y; m[8] *= z; m[1] *= x; m[5] *= y; m[9] *= z; m[2] *= x; m[6] *= y; m[10] *= z; m[3] *= x; m[7] *= y; m[11] *= z; if (FABSF(x - y) < 1e-8 && FABSF(x - z) < 1e-8) mat->flags |= MAT_FLAG_UNIFORM_SCALE; else mat->flags |= MAT_FLAG_GENERAL_SCALE;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -