mirror of
https://github.com/brl/mutter.git
synced 2024-11-25 01:20:42 -05:00
cogl/matrix: Rotate using graphene
This commit is contained in:
parent
d0590de9e8
commit
1aac180e8d
@ -98,20 +98,6 @@ static float identity[16] = {
|
||||
0.0, 0.0, 0.0, 1.0
|
||||
};
|
||||
|
||||
static void
|
||||
matrix_multiply_array_with_flags (CoglMatrix *result,
|
||||
const float *array)
|
||||
{
|
||||
graphene_matrix_t m1, m2, res;
|
||||
|
||||
cogl_matrix_to_graphene_matrix (result, &m1);
|
||||
graphene_matrix_init_from_float (&m2, array);
|
||||
|
||||
graphene_matrix_multiply (&m2, &m1, &res);
|
||||
graphene_matrix_to_cogl_matrix (&res, result);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
cogl_matrix_multiply (CoglMatrix *result,
|
||||
const CoglMatrix *a,
|
||||
@ -166,201 +152,6 @@ cogl_matrix_get_inverse (const CoglMatrix *matrix, CoglMatrix *inverse)
|
||||
return success;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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).
|
||||
*/
|
||||
static void
|
||||
_cogl_matrix_rotate (CoglMatrix *matrix,
|
||||
float angle,
|
||||
float x,
|
||||
float y,
|
||||
float z)
|
||||
{
|
||||
float xx, yy, zz, xy, yz, zx, xs, ys, zs, one_c, s, c;
|
||||
float m[16];
|
||||
gboolean optimized;
|
||||
|
||||
s = sinf (angle * DEG2RAD);
|
||||
c = cosf (angle * DEG2RAD);
|
||||
|
||||
memcpy (m, identity, 16 * sizeof (float));
|
||||
optimized = FALSE;
|
||||
|
||||
#define M(row,col) m[col*4+row]
|
||||
|
||||
if (x == 0.0f)
|
||||
{
|
||||
if (y == 0.0f)
|
||||
{
|
||||
if (z != 0.0f)
|
||||
{
|
||||
optimized = 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 = 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 = 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 float 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_multiply_array_with_flags (matrix, m);
|
||||
}
|
||||
|
||||
void
|
||||
cogl_matrix_rotate (CoglMatrix *matrix,
|
||||
float angle,
|
||||
@ -368,7 +159,17 @@ cogl_matrix_rotate (CoglMatrix *matrix,
|
||||
float y,
|
||||
float z)
|
||||
{
|
||||
_cogl_matrix_rotate (matrix, angle, x, y, z);
|
||||
graphene_matrix_t rotation, m;
|
||||
graphene_vec3_t r;
|
||||
|
||||
cogl_matrix_to_graphene_matrix (matrix, &m);
|
||||
graphene_matrix_transpose (&m, &m);
|
||||
|
||||
graphene_matrix_init_rotate (&rotation, angle, graphene_vec3_init (&r, x, y, z));
|
||||
graphene_matrix_multiply (&rotation, &m, &m);
|
||||
|
||||
graphene_matrix_to_cogl_matrix (&m, matrix);
|
||||
|
||||
_COGL_MATRIX_DEBUG_PRINT (matrix);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user