📄 m_matrix.c
字号:
#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 (fabs(x - y) < 1e-8 && fabs(x - z) < 1e-8)
mat->flags |= MAT_FLAG_UNIFORM_SCALE;
else
mat->flags |= MAT_FLAG_GENERAL_SCALE;
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);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -