From 18193e5322500b9cd3f372223b33581558758312 Mon Sep 17 00:00:00 2001 From: Robert Bragg Date: Tue, 26 May 2009 11:33:54 +0100 Subject: [PATCH] [cogl matrix] Support ortho and perspective projections. This adds cogl_matrix api for multiplying matrices either by a perspective or ortho projective transform. The internal matrix stack and current-matrix APIs also have corresponding support added. New public API: cogl_matrix_perspective cogl_matrix_ortho cogl_ortho cogl_set_modelview_matrix cogl_set_projection_matrix --- cogl-matrix.h | 70 +++++++-- cogl.h.in | 39 +++++ common/cogl-current-matrix.c | 213 +++++++++++++++------------ common/cogl-matrix-stack.c | 72 ++++++--- common/cogl-matrix-stack.h | 20 ++- common/cogl-matrix.c | 87 +++++++++-- doc/reference/cogl/cogl-sections.txt | 19 ++- 7 files changed, 371 insertions(+), 149 deletions(-) diff --git a/cogl-matrix.h b/cogl-matrix.h index ca643f146..bd7b579c7 100644 --- a/cogl-matrix.h +++ b/cogl-matrix.h @@ -199,22 +199,50 @@ void cogl_matrix_frustum (CoglMatrix *matrix, float z_far); /** - * cogl_matrix_transform_point: + * cogl_matrix_perspective: * @matrix: A 4x4 transformation matrix - * @x: The X component of your points position [in:out] - * @y: The Y component of your points position [in:out] - * @z: The Z component of your points position [in:out] - * @w: The W component of your points position [in:out] + * @fov_y: A field of view angle for the Y axis + * @aspect: The ratio of width to height determining the field of view angle + * for the x axis. + * @z_near: The distance to the near clip plane. + * Never pass 0 and always pass a positive number. + * @z_far: The distance to the far clip plane. (Should always be positive) * - * This transforms a point whos position is given and returned - * as four float components. + * Multiplies the matrix by the described perspective matrix + * + * Note: you should be careful not to have to great a z_far / z_near ratio + * since that will reduce the effectiveness of depth testing since there wont + * be enough precision to identify the depth of objects near to each other. */ void -cogl_matrix_transform_point (const CoglMatrix *matrix, - float *x, - float *y, - float *z, - float *w); +cogl_matrix_perspective (CoglMatrix *matrix, + float fov_y, + float aspect, + float z_near, + float z_far); + +/** + * cogl_matrix_ortho: + * @matrix: A 4x4 transformation matrix + * @left: The coordinate for the left clipping plane + * @right: The coordinate for the right clipping plane + * @bottom: The coordinate for the bottom clipping plane + * @top: The coordinate for the top clipping plane + * @near: The coordinate for the near clipping plane (may be negative if + * the plane is behind the viewer) + * @far: The coordinate for the far clipping plane (may be negative if + * the plane is behind the viewer) + * + * Multiples the matrix by a parallel projection matrix. + */ +void +cogl_matrix_ortho (CoglMatrix *matrix, + float left, + float right, + float bottom, + float top, + float near, + float far); /** * cogl_matrix_init_from_array: @@ -234,6 +262,24 @@ void cogl_matrix_init_from_array (CoglMatrix *matrix, const float *array); */ const float *cogl_matrix_get_array (const CoglMatrix *matrix); +/** + * cogl_matrix_transform_point: + * @matrix: A 4x4 transformation matrix + * @x: The X component of your points position [in:out] + * @y: The Y component of your points position [in:out] + * @z: The Z component of your points position [in:out] + * @w: The W component of your points position [in:out] + * + * This transforms a point whos position is given and returned + * as four float components. + */ +void +cogl_matrix_transform_point (const CoglMatrix *matrix, + float *x, + float *y, + float *z, + float *w); + G_END_DECLS #endif /* __COGL_MATRIX_H */ diff --git a/cogl.h.in b/cogl.h.in index b5bb55d10..e66cbc394 100644 --- a/cogl.h.in +++ b/cogl.h.in @@ -170,6 +170,29 @@ void cogl_frustum (float left, float z_near, float z_far); +/** + * cogl_ortho: + * @left: The coordinate for the left clipping plane + * @right: The coordinate for the right clipping plane + * @bottom: The coordinate for the bottom clipping plane + * @top: The coordinate for the top clipping plane + * @near: The coordinate for the near clipping plane (may be negative if + * the plane is behind the viewer) + * @far: The coordinate for the far clipping plane (may be negative if + * the plane is behind the viewer) + * + * Replaces the current projection matrix with a parallel projection + * matrix. + * + * Since: 1.0 + */ +void cogl_ortho (float left, + float right, + float bottom, + float top, + float near, + float far); + /** * cogl_setup_viewport: * @width: Width of the viewport @@ -272,6 +295,14 @@ void cogl_rotate (float angle, */ void cogl_get_modelview_matrix (CoglMatrix *matrix); +/** + * cogl_set_modelview_matrix: + * @matrix: pointer to a CoglMatrix to set as the new model-view matrix + * + * Loads matrix as the new model-view matrix. + */ +void cogl_set_modelview_matrix (CoglMatrix *matrix); + /** * cogl_get_projection_matrix: * @matrix: pointer to a CoglMatrix to recieve the matrix @@ -280,6 +311,14 @@ void cogl_get_modelview_matrix (CoglMatrix *matrix); */ void cogl_get_projection_matrix (CoglMatrix *matrix); +/** + * cogl_set_projection_matrix: + * @matrix: pointer to a CoglMatrix to set as the new projection matrix + * + * Loads matrix as the new projection matrix. + */ +void cogl_set_projection_matrix (CoglMatrix *matrix); + /** * cogl_get_viewport: * @v: pointer to a 4 element array of #floats to diff --git a/common/cogl-current-matrix.c b/common/cogl-current-matrix.c index 0080af0d1..e01987c95 100644 --- a/common/cogl-current-matrix.c +++ b/common/cogl-current-matrix.c @@ -45,6 +45,9 @@ #define glFrustum(L,R,B,T,N,F) \ glFrustumf((GLfloat)L, (GLfloat)R, (GLfloat)B, \ (GLfloat)T, (GLfloat)N, (GLfloat)F) + +#define glOrtho glOrthof + #endif #include @@ -209,30 +212,57 @@ _cogl_current_matrix_frustum (float left, } void -_cogl_current_matrix_ortho (float left, - float right, - float bottom, - float top, - float near_val, - float far_val) +_cogl_current_matrix_perspective (float fov_y, + float aspect, + float z_near, + float z_far) +{ + _COGL_GET_CONTEXT_AND_STACK (ctx, current_stack, NO_RETVAL); + + if (current_stack != NULL) + _cogl_matrix_stack_perspective (current_stack, + fov_y, aspect, z_near, z_far); + else + { + /* NB: There is no glPerspective() (only gluPerspective()) so we use + * cogl_matrix_perspective: */ + CoglMatrix matrix; + _cogl_get_matrix (ctx->matrix_mode, &matrix); + cogl_matrix_perspective (&matrix, + fov_y, aspect, z_near, z_far); + _cogl_current_matrix_load (&matrix); + } +} + +void +_cogl_current_matrix_ortho (float left, + float right, + float bottom, + float top, + float near, + float far) { -#if 0 _COGL_GET_CONTEXT_AND_STACK (ctx, current_stack, NO_RETVAL); if (current_stack != NULL) _cogl_matrix_stack_ortho (current_stack, left, right, - top, bottom, - near_val, - far_val); + bottom, top, + near, + far); else - GE (glOrtho (left, right, bottom, top, near_val, far_val)); + { +#ifdef HAVE_COGL_GLES2 + /* NB: GLES 2 has no glOrtho(): */ + CoglMatrix matrix; + _cogl_get_matrix (ctx->matrix_mode, &matrix); + cogl_matrix_ortho (&matrix, + left, right, bottom, top, near, far); + _cogl_current_matrix_load (&matrix); #else - /* Nobody is using glOrtho right now anyway, so not bothering */ - g_warning ("%s not implemented, need to code cogl_matrix_ortho() if you need" - " this function", - G_STRFUNC); + GE (glOrtho (left, right, bottom, top, near, far)); #endif + } } void @@ -276,6 +306,12 @@ _cogl_get_matrix (CoglMatrixMode mode, } } +void +_cogl_set_matrix (const CoglMatrix *matrix) +{ + _cogl_current_matrix_load (matrix); +} + void _cogl_current_matrix_state_init (void) { @@ -354,85 +390,19 @@ cogl_rotate (float angle, float x, float y, float z) } void -_cogl_set_matrix (const CoglMatrix *matrix) -{ - _cogl_current_matrix_load (matrix); -} - -void -cogl_get_modelview_matrix (CoglMatrix *matrix) -{ - _cogl_get_matrix (COGL_MATRIX_MODELVIEW, - matrix); -} - -void -cogl_get_projection_matrix (CoglMatrix *matrix) -{ - _cogl_get_matrix (COGL_MATRIX_PROJECTION, - matrix); -} - -void -cogl_perspective (float fovy, +cogl_perspective (float fov_y, float aspect, - float zNear, - float zFar) + float z_near, + float z_far) { - float xmax, ymax; - float x, y, c, d; - float fovy_rad_half = (fovy * G_PI) / 360; - CoglMatrix perspective; - GLfloat m[16]; + float ymax = z_near * tanf (fov_y * G_PI / 360.0); - _COGL_GET_CONTEXT (ctx, NO_RETVAL); - - memset (&m[0], 0, sizeof (m)); - - _cogl_set_current_matrix (COGL_MATRIX_PROJECTION); - _cogl_current_matrix_identity (); - - /* - * Based on the original algorithm in perspective(): - * - * 1) xmin = -xmax => xmax + xmin == 0 && xmax - xmin == 2 * xmax - * same true for y, hence: a == 0 && b == 0; - * - * 2) When working with small numbers, we are loosing significant - * precision - */ - ymax = (zNear * (sinf (fovy_rad_half) / cosf (fovy_rad_half))); - xmax = (ymax * aspect); - - x = (zNear / xmax); - y = (zNear / ymax); - c = (-(zFar + zNear) / ( zFar - zNear)); - d = (-(2 * zFar) * zNear) / (zFar - zNear); - -#define M(row,col) m[col*4+row] - M(0,0) = x; - M(1,1) = y; - M(2,2) = c; - M(2,3) = d; - M(3,2) = -1.0; - - cogl_matrix_init_from_array (&perspective, m); - _cogl_current_matrix_multiply (&perspective); - - _cogl_set_current_matrix (COGL_MATRIX_MODELVIEW); - - /* Calculate and store the inverse of the matrix */ - memset (ctx->inverse_projection, 0, sizeof (float) * 16); - -#define m ctx->inverse_projection - M(0, 0) = (1.0 / x); - M(1, 1) = (1.0 / y); - M(2, 3) = -1.0; - M(3, 2) = (1.0 / d); - M(3, 3) = (c / d); -#undef m - -#undef M + cogl_frustum (-ymax * aspect, /* left */ + ymax * aspect, /* right */ + -ymax, /* bottom */ + ymax, /* top */ + z_near, + z_far); } void @@ -474,4 +444,65 @@ cogl_frustum (float left, M(3,2) = 1.0 / d; M(3,3) = c / d; #undef M + + _cogl_set_current_matrix (COGL_MATRIX_MODELVIEW); } + +void +cogl_ortho (float left, + float right, + float bottom, + float top, + float near, + float far) +{ + CoglMatrix ortho; + _COGL_GET_CONTEXT (ctx, NO_RETVAL); + + cogl_matrix_init_identity (&ortho); + cogl_matrix_ortho (&ortho, left, right, bottom, top, near, far); + _cogl_set_current_matrix (COGL_MATRIX_PROJECTION); + _cogl_current_matrix_load (&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 +cogl_get_modelview_matrix (CoglMatrix *matrix) +{ + _cogl_get_matrix (COGL_MATRIX_MODELVIEW, + matrix); +} + +void +cogl_set_modelview_matrix (CoglMatrix *matrix) +{ + _cogl_set_current_matrix (COGL_MATRIX_MODELVIEW); + _cogl_current_matrix_load (matrix); +} + +void +cogl_get_projection_matrix (CoglMatrix *matrix) +{ + _cogl_get_matrix (COGL_MATRIX_PROJECTION, + matrix); +} + +void +cogl_set_projection_matrix (CoglMatrix *matrix) +{ + _cogl_set_current_matrix (COGL_MATRIX_PROJECTION); + _cogl_current_matrix_load (matrix); +} + diff --git a/common/cogl-matrix-stack.c b/common/cogl-matrix-stack.c index a72af000d..6ba909840 100644 --- a/common/cogl-matrix-stack.c +++ b/common/cogl-matrix-stack.c @@ -257,6 +257,59 @@ _cogl_matrix_stack_multiply (CoglMatrixStack *stack, stack->flushed_state = NULL; } +void +_cogl_matrix_stack_frustum (CoglMatrixStack *stack, + float left, + float right, + float bottom, + float top, + float z_near, + float z_far) +{ + CoglMatrixState *state; + + state = _cogl_matrix_stack_top_mutable (stack); + cogl_matrix_frustum (&state->matrix, + left, right, bottom, top, + z_near, z_far); + /* mark dirty */ + stack->flushed_state = NULL; +} + +void +_cogl_matrix_stack_perspective (CoglMatrixStack *stack, + float fov_y, + float aspect, + float z_near, + float z_far) +{ + CoglMatrixState *state; + + state = _cogl_matrix_stack_top_mutable (stack); + cogl_matrix_perspective (&state->matrix, + fov_y, aspect, z_near, z_far); + /* mark dirty */ + stack->flushed_state = NULL; +} + +void +_cogl_matrix_stack_ortho (CoglMatrixStack *stack, + float left, + float right, + float bottom, + float top, + float z_near, + float z_far) +{ + CoglMatrixState *state; + + state = _cogl_matrix_stack_top_mutable (stack); + cogl_matrix_ortho (&state->matrix, + left, right, bottom, top, z_near, z_far); + /* mark dirty */ + stack->flushed_state = NULL; +} + void _cogl_matrix_stack_get (CoglMatrixStack *stack, CoglMatrix *matrix) @@ -280,25 +333,6 @@ _cogl_matrix_stack_set (CoglMatrixStack *stack, stack->flushed_state = NULL; } -void -_cogl_matrix_stack_frustum (CoglMatrixStack *stack, - float left, - float right, - float bottom, - float top, - float z_near, - float z_far) -{ - CoglMatrixState *state; - - state = _cogl_matrix_stack_top_mutable (stack); - cogl_matrix_frustum (&state->matrix, - left, right, bottom, top, - z_near, z_far); - /* mark dirty */ - stack->flushed_state = NULL; -} - void _cogl_matrix_stack_flush_to_gl (CoglMatrixStack *stack, GLenum gl_mode) diff --git a/common/cogl-matrix-stack.h b/common/cogl-matrix-stack.h index 00db51685..a766f4bbc 100644 --- a/common/cogl-matrix-stack.h +++ b/common/cogl-matrix-stack.h @@ -51,10 +51,6 @@ void _cogl_matrix_stack_rotate (CoglMatrixStack *stack, float z); void _cogl_matrix_stack_multiply (CoglMatrixStack *stack, const CoglMatrix *matrix); -void _cogl_matrix_stack_get (CoglMatrixStack *stack, - CoglMatrix *matrix); -void _cogl_matrix_stack_set (CoglMatrixStack *stack, - const CoglMatrix *matrix); void _cogl_matrix_stack_frustum (CoglMatrixStack *stack, float left, float right, @@ -62,6 +58,22 @@ void _cogl_matrix_stack_frustum (CoglMatrixStack *stack, float top, float z_near, float z_far); +void _cogl_matrix_stack_perspective (CoglMatrixStack *stack, + float fov_y, + float aspect, + float z_near, + float z_far); +void _cogl_matrix_stack_ortho (CoglMatrixStack *stack, + float left, + float right, + float bottom, + float top, + float z_near, + float z_far); +void _cogl_matrix_stack_get (CoglMatrixStack *stack, + CoglMatrix *matrix); +void _cogl_matrix_stack_set (CoglMatrixStack *stack, + const CoglMatrix *matrix); void _cogl_matrix_stack_flush_to_gl (CoglMatrixStack *stack, GLenum gl_mode); diff --git a/common/cogl-matrix.c b/common/cogl-matrix.c index 6b6f20fae..45f367d73 100644 --- a/common/cogl-matrix.c +++ b/common/cogl-matrix.c @@ -151,21 +151,6 @@ cogl_matrix_invert (CoglMatrix *matrix) } #endif -void -cogl_matrix_transform_point (const CoglMatrix *matrix, - float *x, - float *y, - float *z, - float *w) -{ - float _x = *x, _y = *y, _z = *z, _w = *w; - - *x = matrix->xx * _x + matrix->xy * _y + matrix->xz * _z + matrix->xw * _w; - *y = matrix->yx * _x + matrix->yy * _y + matrix->yz * _z + matrix->yw * _w; - *z = matrix->zx * _x + matrix->zy * _y + matrix->zz * _z + matrix->zw * _w; - *w = matrix->wx * _x + matrix->wy * _y + matrix->wz * _z + matrix->ww * _w; -} - void cogl_matrix_frustum (CoglMatrix *matrix, float left, @@ -208,6 +193,62 @@ cogl_matrix_frustum (CoglMatrix *matrix, cogl_matrix_multiply (matrix, matrix, &frustum); } +void +cogl_matrix_perspective (CoglMatrix *matrix, + float fov_y, + float aspect, + float z_near, + float z_far) +{ + float ymax = z_near * tan (fov_y * G_PI / 360.0); + + cogl_matrix_frustum (matrix, + -ymax * aspect, /* left */ + ymax * aspect, /* right */ + -ymax, /* bottom */ + ymax, /* top */ + z_near, + z_far); +} + +void +cogl_matrix_ortho (CoglMatrix *matrix, + float left, + float right, + float bottom, + float top, + float near, + float far) +{ + CoglMatrix ortho; + + /* column 0 */ + ortho.xx = 2.0 / (right - left); + ortho.yx = 0.0; + ortho.zx = 0.0; + ortho.wx = 0.0; + + /* column 1 */ + ortho.xy = 0.0; + ortho.yy = 2.0 / (top - bottom); + ortho.zy = 0.0; + ortho.wy = 0.0; + + /* column 2 */ + ortho.xz = 0.0; + ortho.yz = 0.0; + ortho.zz = -2.0 / (far - near); + ortho.wz = 0.0; + + /* column 3 */ + ortho.xw = -(right + left) / (right - left); + ortho.yw = -(top + bottom) / (top - bottom); + ortho.zw = -(far + near) / (far - near); + ortho.ww = 1.0; + + cogl_matrix_multiply (matrix, matrix, &ortho); +} + void cogl_matrix_init_from_array (CoglMatrix *matrix, const float *array) { @@ -220,3 +261,19 @@ cogl_matrix_get_array (const CoglMatrix *matrix) return (float *)matrix; } +void +cogl_matrix_transform_point (const CoglMatrix *matrix, + float *x, + float *y, + float *z, + float *w) +{ + float _x = *x, _y = *y, _z = *z, _w = *w; + + *x = matrix->xx * _x + matrix->xy * _y + matrix->xz * _z + matrix->xw * _w; + *y = matrix->yx * _x + matrix->yy * _y + matrix->yz * _z + matrix->yw * _w; + *z = matrix->zx * _x + matrix->zy * _y + matrix->zz * _z + matrix->zw * _w; + *w = matrix->wx * _x + matrix->wy * _y + matrix->wz * _z + matrix->ww * _w; +} + + diff --git a/doc/reference/cogl/cogl-sections.txt b/doc/reference/cogl/cogl-sections.txt index 6ee2d9517..5855a90b1 100644 --- a/doc/reference/cogl/cogl-sections.txt +++ b/doc/reference/cogl/cogl-sections.txt @@ -21,19 +21,22 @@ cogl_features_available cogl_check_extension cogl_get_proc_address -cogl_perspective -cogl_frustum -cogl_setup_viewport -cogl_viewport -cogl_get_modelview_matrix -cogl_get_projection_matrix -cogl_get_viewport - cogl_push_matrix cogl_pop_matrix cogl_scale cogl_translate cogl_rotate +cogl_frustum +cogl_perspective +cogl_ortho + +cogl_get_modelview_matrix +cogl_set_modelview_matrix +cogl_get_projection_matrix +cogl_set_projection_matrix +cogl_viewport +cogl_setup_viewport +cogl_get_viewport cogl_clear cogl_get_bitmasks