cogl/matrix: Rotate using graphene

This commit is contained in:
Georges Basile Stavracas Neto 2019-02-27 20:42:02 -03:00
parent d0590de9e8
commit 1aac180e8d
No known key found for this signature in database
GPG Key ID: 886C17EE170D1385

View File

@ -98,20 +98,6 @@ static float identity[16] = {
0.0, 0.0, 0.0, 1.0 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 void
cogl_matrix_multiply (CoglMatrix *result, cogl_matrix_multiply (CoglMatrix *result,
const CoglMatrix *a, const CoglMatrix *a,
@ -166,201 +152,6 @@ cogl_matrix_get_inverse (const CoglMatrix *matrix, CoglMatrix *inverse)
return success; 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 void
cogl_matrix_rotate (CoglMatrix *matrix, cogl_matrix_rotate (CoglMatrix *matrix,
float angle, float angle,
@ -368,7 +159,17 @@ cogl_matrix_rotate (CoglMatrix *matrix,
float y, float y,
float z) 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); _COGL_MATRIX_DEBUG_PRINT (matrix);
} }