/** * Multiply a matrix by an array of floats with known properties. * * \param mat pointer to a GLmatrix structure containing the left multiplication * matrix, and that will receive the product result. * \param m right multiplication matrix array. * \param flags flags of the matrix \p m. * * Joins both flags and marks the type and inverse as dirty. Calls matmul34() * if both matrices are 3D, or matmul4() otherwise. */ static void matrix_multf( GLmatrix *mat, const GLfloat *m, GLuint flags ) { mat->flags |= (flags | MAT_DIRTY_TYPE | MAT_DIRTY_INVERSE); if (TEST_MAT_FLAGS(mat, MAT_FLAGS_3D)) matmul34( mat->m, mat->m, m ); else matmul4( mat->m, mat->m, m ); }
/** * Matrix multiplication. * * \param dest destination matrix. * \param a left matrix. * \param b right matrix. * * Joins both flags and marks the type and inverse as dirty. Calls matmul34() * if both matrices are 3D, or matmul4() otherwise. */ void _math_matrix_mul_matrix( GLmatrix *dest, const GLmatrix *a, const GLmatrix *b ) { dest->flags = (a->flags | b->flags | MAT_DIRTY_TYPE | MAT_DIRTY_INVERSE); if (TEST_MAT_FLAGS(dest, MAT_FLAGS_3D)) matmul34( dest->m, a->m, b->m ); else matmul4( dest->m, a->m, b->m ); }
/** * 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; } }
/* * If ctx->NewState is non-zero then this function MUST be called before * rendering any primitive. Basically, function pointers and miscellaneous * flags are updated to reflect the current state of the state machine. * * The above constraint is now maintained largely by the two Exec * dispatch tables, which trigger the appropriate flush on transition * between State and Geometry modes. * * Special care is taken with the derived value _NeedEyeCoords. This * is a bitflag which is updated with information from a number of * attribute groups (MODELVIEW, LIGHT, TEXTURE). A lot of derived * state references this value, and must be treated with care to * ensure that updates are done correctly. All state dependent on * _NeedEyeCoords is calculated from within _mesa_update_tnl_spaces(), * and from nowhere else. */ void _mesa_update_state( GLcontext *ctx ) { const GLuint new_state = ctx->NewState; const GLuint oldneedeyecoords = ctx->_NeedEyeCoords; if (MESA_VERBOSE & VERBOSE_STATE) _mesa_print_state("_mesa_update_state", new_state); if (new_state & _NEW_MODELVIEW) _math_matrix_analyse( &ctx->ModelView ); if (new_state & _NEW_PROJECTION) update_projection( ctx ); if (new_state & _NEW_TEXTURE_MATRIX) update_texture_matrices( ctx ); if (new_state & _NEW_COLOR_MATRIX) _math_matrix_analyse( &ctx->ColorMatrix ); /* References ColorMatrix.type (derived above). */ if (new_state & _IMAGE_NEW_TRANSFER_STATE) update_image_transfer_state(ctx); /* Contributes to NeedEyeCoords, NeedNormals. */ if (new_state & _NEW_TEXTURE) update_texture_state( ctx ); if (new_state & (_NEW_BUFFERS|_NEW_SCISSOR)) update_drawbuffer( ctx ); if (new_state & _NEW_POLYGON) update_polygon( ctx ); /* Contributes to NeedEyeCoords, NeedNormals. */ if (new_state & _NEW_LIGHT) _mesa_update_lighting( ctx ); /* We can light in object space if the modelview matrix preserves * lengths and relative angles. */ if (new_state & (_NEW_MODELVIEW|_NEW_LIGHT)) { ctx->_NeedEyeCoords &= ~NEED_EYE_LIGHT_MODELVIEW; if (ctx->Light.Enabled && !TEST_MAT_FLAGS( &ctx->ModelView, MAT_FLAGS_LENGTH_PRESERVING)) ctx->_NeedEyeCoords |= NEED_EYE_LIGHT_MODELVIEW; } /* Keep ModelviewProject uptodate always to allow tnl * implementations that go model->clip even when eye is required. */ if (new_state & (_NEW_MODELVIEW|_NEW_PROJECTION)) calculate_model_project_matrix(ctx); /* ctx->_NeedEyeCoords is now uptodate. * * If the truth value of this variable has changed, update for the * new lighting space and recompute the positions of lights and the * normal transform. * * If the lighting space hasn't changed, may still need to recompute * light positions & normal transforms for other reasons. */ if (new_state & (_NEW_MODELVIEW | _NEW_LIGHT | _MESA_NEW_NEED_EYE_COORDS)) update_tnl_spaces( ctx, oldneedeyecoords ); /* * Here the driver sets up all the ctx->Driver function pointers * to it's specific, private functions, and performs any * internal state management necessary, including invalidating * state of active modules. * * Set ctx->NewState to zero to avoid recursion if * Driver.UpdateState() has to call FLUSH_VERTICES(). (fixed?) */ ctx->NewState = 0; ctx->Driver.UpdateState(ctx, new_state); ctx->Array.NewState = 0; /* At this point we can do some assertions to be sure the required * device driver function pointers are all initialized. */ ASSERT(ctx->Driver.GetString); ASSERT(ctx->Driver.UpdateState); ASSERT(ctx->Driver.Clear); ASSERT(ctx->Driver.SetDrawBuffer); ASSERT(ctx->Driver.GetBufferSize); if (ctx->Visual.accumRedBits > 0) { ASSERT(ctx->Driver.Accum); } ASSERT(ctx->Driver.DrawPixels); ASSERT(ctx->Driver.ReadPixels); ASSERT(ctx->Driver.CopyPixels); ASSERT(ctx->Driver.Bitmap); ASSERT(ctx->Driver.ResizeBuffers); ASSERT(ctx->Driver.TexImage1D); ASSERT(ctx->Driver.TexImage2D); ASSERT(ctx->Driver.TexImage3D); ASSERT(ctx->Driver.TexSubImage1D); ASSERT(ctx->Driver.TexSubImage2D); ASSERT(ctx->Driver.TexSubImage3D); ASSERT(ctx->Driver.CopyTexImage1D); ASSERT(ctx->Driver.CopyTexImage2D); ASSERT(ctx->Driver.CopyTexSubImage1D); ASSERT(ctx->Driver.CopyTexSubImage2D); ASSERT(ctx->Driver.CopyTexSubImage3D); if (ctx->Extensions.ARB_texture_compression) { ASSERT(ctx->Driver.BaseCompressedTexFormat); ASSERT(ctx->Driver.CompressedTextureSize); ASSERT(ctx->Driver.GetCompressedTexImage); #if 0 /* HW drivers need these, but not SW rasterizers */ ASSERT(ctx->Driver.CompressedTexImage1D); ASSERT(ctx->Driver.CompressedTexImage2D); ASSERT(ctx->Driver.CompressedTexImage3D); ASSERT(ctx->Driver.CompressedTexSubImage1D); ASSERT(ctx->Driver.CompressedTexSubImage2D); ASSERT(ctx->Driver.CompressedTexSubImage3D); #endif } }
/** * 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; }
/** * 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); }