[matrix] Adds cogl_matrix_get_inverse API

This new API takes advantage of the recently imported Mesa code to support
inverse matrix calculation.  The matrix code keeps track (via internal
flags) of the transformations a matrix represents so that it can select an
optimized inversion function.

Note: although other aspects of the Cogl matrix API have followed a similar
style to Cairo's matrix API we haven't added a cogl_matrix_invert API
because the inverse of a CoglMatrix is actually cached as part of the
CoglMatrix structure meaning a destructive API like cogl_matrix_invert
doesn't let users take advantage of this caching design.
This commit is contained in:
Robert Bragg 2009-10-26 17:51:34 +00:00
parent 8051596e96
commit 0369a1b84d
6 changed files with 65 additions and 53 deletions

View File

@ -61,9 +61,6 @@ typedef struct
CoglMatrixMode flushed_matrix_mode;
GList *texture_units;
/* Cache of inverse projection matrix */
float inverse_projection[16];
/* Materials */
CoglHandle default_material;
CoglHandle source_material;

View File

@ -348,6 +348,17 @@ _cogl_matrix_stack_ortho (CoglMatrixStack *stack,
state->is_identity = FALSE;
}
gboolean
_cogl_matrix_stack_get_inverse (CoglMatrixStack *stack,
CoglMatrix *inverse)
{
CoglMatrixState *state;
state = _cogl_matrix_stack_top_mutable (stack, TRUE);
return cogl_matrix_get_inverse (&state->matrix, inverse);
}
void
_cogl_matrix_stack_get (CoglMatrixStack *stack,
CoglMatrix *matrix)

View File

@ -71,6 +71,9 @@ void _cogl_matrix_stack_ortho (CoglMatrixStack *stack,
float top,
float z_near,
float z_far);
gboolean _cogl_matrix_stack_get_inverse (CoglMatrixStack *stack,
CoglMatrix *inverse);
void _cogl_matrix_stack_get (CoglMatrixStack *stack,
CoglMatrix *matrix);
void _cogl_matrix_stack_set (CoglMatrixStack *stack,

View File

@ -183,18 +183,6 @@ cogl_matrix_scale (CoglMatrix *matrix,
_COGL_MATRIX_DEBUG_PRINT (matrix);
}
#if 0
gboolean
cogl_matrix_invert (CoglMatrix *matrix)
{
/* TODO */
/* Note: It might be nice to also use the flag based tricks that mesa does
* to alow it to track the type of transformations a matrix represents
* so it can use various assumptions to optimise the inversion.
*/
}
#endif
void
cogl_matrix_frustum (CoglMatrix *matrix,
float left,
@ -321,6 +309,27 @@ cogl_matrix_get_array (const CoglMatrix *matrix)
return (float *)matrix;
}
gboolean
cogl_matrix_get_inverse (const CoglMatrix *matrix, CoglMatrix *inverse)
{
#ifndef USE_MESA_MATRIX_API
#warning "cogl_matrix_get_inverse not supported without Mesa matrix API"
cogl_matrix_init_identity (inverse);
return FALSE;
#else
if (_math_matrix_update_inverse ((CoglMatrix *)matrix))
{
cogl_matrix_init_from_array (inverse, matrix->inv);
return TRUE;
}
else
{
cogl_matrix_init_identity (inverse);
return FALSE;
}
#endif
}
void
cogl_matrix_transform_point (const CoglMatrix *matrix,
float *x,

View File

@ -266,6 +266,27 @@ void cogl_matrix_init_from_array (CoglMatrix *matrix, const float *array);
*/
G_CONST_RETURN float *cogl_matrix_get_array (const CoglMatrix *matrix);
/**
* cogl_matrix_get_inverse:
* @matrix: A 4x4 transformation matrix
* @inverse: The destination for a 4x4 inverse transformation matrix
*
* This gets the inverse transform of a given matrix and uses it to initialize
* a new CoglMatrix.
*
* Note: that although the first parameter is annotated as const to indicate
* that the transform it represents isn't modified this function may
* technically save a copy of the inverse transform within the given CoglMatrix
* so that subsequent requests for the inverse transform may avoid costly
* inversion calculations.
*
* Returns TRUE if the inverse was successfully calculated or FALSE for
* degenerate transformations that can't be inverted (in this case the matrix
* will simply be initialized with the identity matrix)
*/
gboolean
cogl_matrix_get_inverse (const CoglMatrix *matrix, CoglMatrix *inverse);
/**
* cogl_matrix_transform_point:
* @matrix: A 4x4 transformation matrix

View File

@ -368,13 +368,17 @@ set_clip_plane (GLint plane_num,
GLdouble plane[4];
#endif
GLfloat angle;
CoglMatrix inverse_projection;
CoglHandle draw_buffer = _cogl_get_draw_buffer ();
CoglMatrixStack *modelview_stack =
_cogl_draw_buffer_get_modelview_stack (draw_buffer);
CoglMatrixStack *projection_stack =
_cogl_draw_buffer_get_projection_stack (draw_buffer);
CoglMatrix inverse_projection;
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
_cogl_matrix_stack_get_inverse (projection_stack, &inverse_projection);
/* Calculate the angle between the axes and the line crossing the
two points */
angle = atan2f (vertex_b[1] - vertex_a[1],
@ -382,13 +386,10 @@ set_clip_plane (GLint plane_num,
_cogl_matrix_stack_push (modelview_stack);
/* Load the identity matrix and multiply by the reverse of the
projection matrix so we can specify the plane in screen
coordinates */
_cogl_matrix_stack_load_identity (modelview_stack);
cogl_matrix_init_from_array (&inverse_projection,
ctx->inverse_projection);
_cogl_matrix_stack_multiply (modelview_stack, &inverse_projection);
/* Load the inverse of the projection matrix so we can specify the plane
* in screen coordinates */
_cogl_matrix_stack_set (modelview_stack, &inverse_projection);
/* Rotate about point a */
_cogl_matrix_stack_translate (modelview_stack,
vertex_a[0], vertex_a[1], vertex_a[2]);
@ -1095,7 +1096,6 @@ cogl_frustum (float left,
float z_near,
float z_far)
{
float c, d;
CoglMatrixStack *projection_stack =
_cogl_draw_buffer_get_projection_stack (_cogl_get_draw_buffer ());
@ -1110,22 +1110,6 @@ cogl_frustum (float left,
top,
z_near,
z_far);
/* Calculate and store the inverse of the matrix */
memset (ctx->inverse_projection, 0, sizeof (float) * 16);
c = - (z_far + z_near) / (z_far - z_near);
d = - (2 * (z_far * z_near)) / (z_far - z_near);
#define M(row,col) ctx->inverse_projection[col*4+row]
M(0,0) = (right - left) / (2 * z_near);
M(0,3) = (right + left) / (2 * z_near);
M(1,1) = (top - bottom) / (2 * z_near);
M(1,3) = (top + bottom) / (2 * z_near);
M(2,3) = -1.0;
M(3,2) = 1.0 / d;
M(3,3) = c / d;
#undef M
}
void
@ -1145,19 +1129,6 @@ cogl_ortho (float left,
cogl_matrix_init_identity (&ortho);
cogl_matrix_ortho (&ortho, left, right, bottom, top, z_near, z_far);
_cogl_matrix_stack_set (projection_stack, &ortho);
/* Calculate and store the inverse of the matrix */
memset (ctx->inverse_projection, 0, sizeof (float) * 16);
#define M(row,col) ctx->inverse_projection[col*4+row]
M(0,0) = 1.0 / ortho.xx;
M(0,3) = -ortho.xw;
M(1,1) = 1.0 / ortho.yy;
M(1,3) = -ortho.yw;
M(2,2) = 1.0 / ortho.zz;
M(2,3) = -ortho.zw;
M(3,3) = 1.0;
#undef M
}
void