From 28c7e940bf322f96233534f6b769ccd1bcd3b14e Mon Sep 17 00:00:00 2001 From: Robert Bragg Date: Mon, 26 Oct 2009 17:51:34 +0000 Subject: [PATCH] [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. --- cogl/cogl-context.h | 3 --- cogl/cogl-matrix-stack.c | 11 ++++++++++ cogl/cogl-matrix-stack.h | 3 +++ cogl/cogl-matrix.c | 33 ++++++++++++++++++---------- cogl/cogl-matrix.h | 21 ++++++++++++++++++ cogl/cogl.c | 47 ++++++++-------------------------------- 6 files changed, 65 insertions(+), 53 deletions(-) diff --git a/cogl/cogl-context.h b/cogl/cogl-context.h index 9d2aa077a..d10664f30 100644 --- a/cogl/cogl-context.h +++ b/cogl/cogl-context.h @@ -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; diff --git a/cogl/cogl-matrix-stack.c b/cogl/cogl-matrix-stack.c index 4e2269dbc..c6236efd3 100644 --- a/cogl/cogl-matrix-stack.c +++ b/cogl/cogl-matrix-stack.c @@ -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) diff --git a/cogl/cogl-matrix-stack.h b/cogl/cogl-matrix-stack.h index 1762eda95..648eace84 100644 --- a/cogl/cogl-matrix-stack.h +++ b/cogl/cogl-matrix-stack.h @@ -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, diff --git a/cogl/cogl-matrix.c b/cogl/cogl-matrix.c index 4a4fccf31..5eb0f9782 100644 --- a/cogl/cogl-matrix.c +++ b/cogl/cogl-matrix.c @@ -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, diff --git a/cogl/cogl-matrix.h b/cogl/cogl-matrix.h index 8f0f73de5..19e3e133b 100644 --- a/cogl/cogl-matrix.h +++ b/cogl/cogl-matrix.h @@ -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 diff --git a/cogl/cogl.c b/cogl/cogl.c index 7f556155a..7631eee5b 100644 --- a/cogl/cogl.c +++ b/cogl/cogl.c @@ -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