📄 m_matrix.c
字号:
mat->flags |= (MAT_DIRTY_TYPE | MAT_DIRTY_INVERSE);}/** * Multiply a matrix with a translation matrix. * * \param mat matrix. * \param x translation vector x coordinate. * \param y translation vector y coordinate. * \param z translation vector z coordinate. * * Adds the translation coordinates to the elements of \p mat in-place. Marks * the MAT_FLAG_TRANSLATION flag, and the MAT_DIRTY_TYPE and MAT_DIRTY_INVERSE * dirty flags. */void_math_matrix_translate( GLmatrix *mat, GLfloat x, GLfloat y, GLfloat z ){ GLfloat *m = mat->m; m[12] = m[0] * x + m[4] * y + m[8] * z + m[12]; m[13] = m[1] * x + m[5] * y + m[9] * z + m[13]; m[14] = m[2] * x + m[6] * y + m[10] * z + m[14]; m[15] = m[3] * x + m[7] * y + m[11] * z + m[15]; mat->flags |= (MAT_FLAG_TRANSLATION | MAT_DIRTY_TYPE | MAT_DIRTY_INVERSE);}/** * Set matrix to do viewport and depthrange mapping. * Transforms Normalized Device Coords to window/Z values. */void_math_matrix_viewport(GLmatrix *m, GLint x, GLint y, GLint width, GLint height, GLfloat zNear, GLfloat zFar, GLfloat depthMax){ m->m[MAT_SX] = (GLfloat) width / 2.0F; m->m[MAT_TX] = m->m[MAT_SX] + x; m->m[MAT_SY] = (GLfloat) height / 2.0F; m->m[MAT_TY] = m->m[MAT_SY] + y; m->m[MAT_SZ] = depthMax * ((zFar - zNear) / 2.0F); m->m[MAT_TZ] = depthMax * ((zFar - zNear) / 2.0F + zNear); m->flags = MAT_FLAG_GENERAL_SCALE | MAT_FLAG_TRANSLATION; m->type = MATRIX_3D_NO_ROT;}/** * Set a matrix to the identity matrix. * * \param mat matrix. * * Copies ::Identity into \p GLmatrix::m, and into GLmatrix::inv if not NULL. * Sets the matrix type to identity, and clear the dirty flags. */void_math_matrix_set_identity( GLmatrix *mat ){ MEMCPY( mat->m, Identity, 16*sizeof(GLfloat) ); if (mat->inv) MEMCPY( mat->inv, Identity, 16*sizeof(GLfloat) ); mat->type = MATRIX_IDENTITY; mat->flags &= ~(MAT_DIRTY_FLAGS| MAT_DIRTY_TYPE| MAT_DIRTY_INVERSE);}/*@}*//**********************************************************************//** \name Matrix analysis *//*@{*/#define ZERO(x) (1<<x)#define ONE(x) (1<<(x+16))#define MASK_NO_TRX (ZERO(12) | ZERO(13) | ZERO(14))#define MASK_NO_2D_SCALE ( ONE(0) | ONE(5))#define MASK_IDENTITY ( ONE(0) | ZERO(4) | ZERO(8) | ZERO(12) |\ ZERO(1) | ONE(5) | ZERO(9) | ZERO(13) |\ ZERO(2) | ZERO(6) | ONE(10) | ZERO(14) |\ ZERO(3) | ZERO(7) | ZERO(11) | ONE(15) )#define MASK_2D_NO_ROT ( ZERO(4) | ZERO(8) | \ ZERO(1) | ZERO(9) | \ ZERO(2) | ZERO(6) | ONE(10) | ZERO(14) |\ ZERO(3) | ZERO(7) | ZERO(11) | ONE(15) )#define MASK_2D ( ZERO(8) | \ ZERO(9) | \ ZERO(2) | ZERO(6) | ONE(10) | ZERO(14) |\ ZERO(3) | ZERO(7) | ZERO(11) | ONE(15) )#define MASK_3D_NO_ROT ( ZERO(4) | ZERO(8) | \ ZERO(1) | ZERO(9) | \ ZERO(2) | ZERO(6) | \ ZERO(3) | ZERO(7) | ZERO(11) | ONE(15) )#define MASK_3D ( \ \ \ ZERO(3) | ZERO(7) | ZERO(11) | ONE(15) )#define MASK_PERSPECTIVE ( ZERO(4) | ZERO(12) |\ ZERO(1) | ZERO(13) |\ ZERO(2) | ZERO(6) | \ ZERO(3) | ZERO(7) | ZERO(15) )#define SQ(x) ((x)*(x))/** * Determine type and flags from scratch. * * \param mat matrix. * * This is expensive enough to only want to do it once. */static void analyse_from_scratch( GLmatrix *mat ){ const GLfloat *m = mat->m; GLuint mask = 0; GLuint i; for (i = 0 ; i < 16 ; i++) { if (m[i] == 0.0) mask |= (1<<i); } if (m[0] == 1.0F) mask |= (1<<16); if (m[5] == 1.0F) mask |= (1<<21); if (m[10] == 1.0F) mask |= (1<<26); if (m[15] == 1.0F) mask |= (1<<31); mat->flags &= ~MAT_FLAGS_GEOMETRY; /* Check for translation - no-one really cares */ if ((mask & MASK_NO_TRX) != MASK_NO_TRX) mat->flags |= MAT_FLAG_TRANSLATION; /* Do the real work */ if (mask == (GLuint) MASK_IDENTITY) { mat->type = MATRIX_IDENTITY; } else if ((mask & MASK_2D_NO_ROT) == (GLuint) MASK_2D_NO_ROT) { mat->type = MATRIX_2D_NO_ROT; if ((mask & MASK_NO_2D_SCALE) != MASK_NO_2D_SCALE) mat->flags |= MAT_FLAG_GENERAL_SCALE; } else if ((mask & MASK_2D) == (GLuint) MASK_2D) { GLfloat mm = DOT2(m, m); GLfloat m4m4 = DOT2(m+4,m+4); GLfloat mm4 = DOT2(m,m+4); mat->type = MATRIX_2D; /* Check for scale */ if (SQ(mm-1) > SQ(1e-6) || SQ(m4m4-1) > SQ(1e-6)) mat->flags |= MAT_FLAG_GENERAL_SCALE; /* Check for rotation */ if (SQ(mm4) > SQ(1e-6)) mat->flags |= MAT_FLAG_GENERAL_3D; else mat->flags |= MAT_FLAG_ROTATION; } else if ((mask & MASK_3D_NO_ROT) == (GLuint) MASK_3D_NO_ROT) { mat->type = MATRIX_3D_NO_ROT; /* Check for scale */ if (SQ(m[0]-m[5]) < SQ(1e-6) && SQ(m[0]-m[10]) < SQ(1e-6)) { if (SQ(m[0]-1.0) > SQ(1e-6)) { mat->flags |= MAT_FLAG_UNIFORM_SCALE; } } else { mat->flags |= MAT_FLAG_GENERAL_SCALE; } } else if ((mask & MASK_3D) == (GLuint) MASK_3D) { GLfloat c1 = DOT3(m,m); GLfloat c2 = DOT3(m+4,m+4); GLfloat c3 = DOT3(m+8,m+8); GLfloat d1 = DOT3(m, m+4); GLfloat cp[3]; mat->type = MATRIX_3D; /* Check for scale */ if (SQ(c1-c2) < SQ(1e-6) && SQ(c1-c3) < SQ(1e-6)) { if (SQ(c1-1.0) > SQ(1e-6)) mat->flags |= MAT_FLAG_UNIFORM_SCALE; /* else no scale at all */ } else { mat->flags |= MAT_FLAG_GENERAL_SCALE; } /* Check for rotation */ if (SQ(d1) < SQ(1e-6)) { CROSS3( cp, m, m+4 ); SUB_3V( cp, cp, (m+8) ); if (LEN_SQUARED_3FV(cp) < SQ(1e-6)) mat->flags |= MAT_FLAG_ROTATION; else mat->flags |= MAT_FLAG_GENERAL_3D; } else { mat->flags |= MAT_FLAG_GENERAL_3D; /* shear, etc */ } } else if ((mask & MASK_PERSPECTIVE) == MASK_PERSPECTIVE && m[11]==-1.0F) { mat->type = MATRIX_PERSPECTIVE; mat->flags |= MAT_FLAG_GENERAL; } else { mat->type = MATRIX_GENERAL; mat->flags |= MAT_FLAG_GENERAL; }}/** * Analyze a matrix given that its flags are accurate. * * This is the more common operation, hopefully. */static void analyse_from_flags( GLmatrix *mat ){ const GLfloat *m = mat->m; if (TEST_MAT_FLAGS(mat, 0)) { mat->type = MATRIX_IDENTITY; } else if (TEST_MAT_FLAGS(mat, (MAT_FLAG_TRANSLATION | MAT_FLAG_UNIFORM_SCALE | MAT_FLAG_GENERAL_SCALE))) { if ( m[10]==1.0F && m[14]==0.0F ) { mat->type = MATRIX_2D_NO_ROT; } else { mat->type = MATRIX_3D_NO_ROT; } } else if (TEST_MAT_FLAGS(mat, MAT_FLAGS_3D)) { if ( m[ 8]==0.0F && m[ 9]==0.0F && m[2]==0.0F && m[6]==0.0F && m[10]==1.0F && m[14]==0.0F) { mat->type = MATRIX_2D; } else { mat->type = MATRIX_3D; } } else if ( m[4]==0.0F && m[12]==0.0F && m[1]==0.0F && m[13]==0.0F && m[2]==0.0F && m[6]==0.0F && m[3]==0.0F && m[7]==0.0F && m[11]==-1.0F && m[15]==0.0F) { mat->type = MATRIX_PERSPECTIVE; } else { mat->type = MATRIX_GENERAL; }}/** * Analyze and update a matrix. * * \param mat matrix. * * If the matrix type is dirty then calls either analyse_from_scratch() or * analyse_from_flags() to determine its type, according to whether the flags * are dirty or not, respectively. If the matrix has an inverse and it's dirty * then calls matrix_invert(). Finally clears the dirty flags. */void_math_matrix_analyse( GLmatrix *mat ){ if (mat->flags & MAT_DIRTY_TYPE) { if (mat->flags & MAT_DIRTY_FLAGS) analyse_from_scratch( mat ); else analyse_from_flags( mat ); } if (mat->inv && (mat->flags & MAT_DIRTY_INVERSE)) { matrix_invert( mat ); } mat->flags &= ~(MAT_DIRTY_FLAGS| MAT_DIRTY_TYPE| MAT_DIRTY_INVERSE);}/*@}*//** * Test if the given matrix preserves vector lengths. */GLboolean_math_matrix_is_length_preserving( const GLmatrix *m ){ return TEST_MAT_FLAGS( m, MAT_FLAGS_LENGTH_PRESERVING);}/** * Test if the given matrix does any rotation. * (or perhaps if the upper-left 3x3 is non-identity) */GLboolean_math_matrix_has_rotation( const GLmatrix *m ){ if (m->flags & (MAT_FLAG_GENERAL | MAT_FLAG_ROTATION | MAT_FLAG_GENERAL_3D | MAT_FLAG_PERSPECTIVE)) return GL_TRUE; else return GL_FALSE;}GLboolean_math_matrix_is_general_scale( const GLmatrix *m ){ return (m->flags & MAT_FLAG_GENERAL_SCALE) ? GL_TRUE : GL_FALSE;}GLboolean_math_matrix_is_dirty( const GLmatrix *m ){ return (m->flags & MAT_DIRTY) ? GL_TRUE : GL_FALSE;}/**********************************************************************//** \name Matrix setup *//*@{*//** * Copy a matrix. * * \param to destination matrix. * \param from source matrix. * * Copies all fields in GLmatrix, creating an inverse array if necessary. */void_math_matrix_copy( GLmatrix *to, const GLmatrix *from ){ MEMCPY( to->m, from->m, sizeof(Identity) ); to->flags = from->flags; to->type = from->type; if (to->inv != 0) { if (from->inv == 0) { matrix_invert( to ); } else { MEMCPY(to->inv, from->inv, sizeof(GLfloat)*16); } }}/** * Loads a matrix array into GLmatrix. * * \param m matrix array. * \param mat matrix. * * Copies \p m into GLmatrix::m and marks the MAT_FLAG_GENERAL and MAT_DIRTY * flags. */void_math_matrix_loadf( GLmatrix *mat, const GLfloat *m ){ MEMCPY( mat->m, m, 16*sizeof(GLfloat) ); mat->flags = (MAT_FLAG_GENERAL | MAT_DIRTY);}/** * Matrix constructor. * * \param m matrix. * * Initialize the GLmatrix fields. */void_math_matrix_ctr( GLmatrix *m ){ m->m = (GLfloat *) ALIGN_MALLOC( 16 * sizeof(GLfloat), 16 ); if (m->m) MEMCPY( m->m, Identity, sizeof(Identity) ); m->inv = NULL; m->type = MATRIX_IDENTITY; m->flags = 0;}/** * Matrix destructor. * * \param m matrix. * * Frees the data in a GLmatrix. */void_math_matrix_dtr( GLmatrix *m ){ if (m->m) { ALIGN_FREE( m->m ); m->m = NULL; } if (m->inv) { ALIGN_FREE( m->inv ); m->inv = NULL; }}/** * Allocate a matrix inverse. * * \param m matrix. * * Allocates the matrix inverse, GLmatrix::inv, and sets it to Identity. */void_math_matrix_alloc_inv( GLmatrix *m ){ if (!m->inv) { m->inv = (GLfloat *) ALIGN_MALLOC( 16 * sizeof(GLfloat), 16 ); if (m->inv) MEMCPY( m->inv, Identity, 16 * sizeof(GLfloat) ); }}/*@}*//**********************************************************************//** \name Matrix transpose *//*@{*//** * Transpose a GLfloat matrix. * * \param to destination array. * \param from source array. */void_math_transposef( GLfloat to[16], const GLfloat from[16] ){ to[0] = from[0]; to[1] = from[4]; to[2] = from[8]; to[3] = from[12]; to[4] = from[1]; to[5] = from[5]; to[6] = from[9]; to[7] = from[13]; to[8] = from[2]; to[9] = from[6]; to[10] = from[10]; to[11] = from[14]; to[12] = from[3]; to[13] = from[7]; to[14] = from[11]; to[15] = from[15];}/** * Transpose a GLdouble matrix. * * \param to destination array. * \param from source array. */void_math_transposed( GLdouble to[16], const GLdouble from[16] ){ to[0] = from[0]; to[1] = from[4]; to[2] = from[8]; to[3] = from[12]; to[4] = from[1]; to[5] = from[5]; to[6] = from[9]; to[7] = from[13]; to[8] = from[2]; to[9] = from[6]; to[10] = from[10]; to[11] = from[14]; to[12] = from[3]; to[13] = from[7]; to[14] = from[11]; to[15] = from[15];}/** * Transpose a GLdouble matrix and convert to GLfloat. * * \param to destination array. * \param from source array. */void_math_transposefd( GLfloat to[16], const GLdouble from[16] ){ to[0] = (GLfloat) from[0]; to[1] = (GLfloat) from[4]; to[2] = (GLfloat) from[8]; to[3] = (GLfloat) from[12]; to[4] = (GLfloat) from[1]; to[5] = (GLfloat) from[5]; to[6] = (GLfloat) from[9]; to[7] = (GLfloat) from[13]; to[8] = (GLfloat) from[2]; to[9] = (GLfloat) from[6]; to[10] = (GLfloat) from[10]; to[11] = (GLfloat) from[14]; to[12] = (GLfloat) from[3]; to[13] = (GLfloat) from[7]; to[14] = (GLfloat) from[11]; to[15] = (GLfloat) from[15];}/*@}*/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -