[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
This commit is contained in:
Robert Bragg 2009-05-26 11:33:54 +01:00
parent 12c8ff8606
commit 96188bab62
7 changed files with 371 additions and 149 deletions

View File

@ -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 */

View File

@ -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 #float<!-- -->s to

View File

@ -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 <string.h>
@ -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);
}

View File

@ -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)

View File

@ -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);

View File

@ -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;
}

View File

@ -21,19 +21,22 @@ cogl_features_available
cogl_check_extension
cogl_get_proc_address
<SUBSECTION>
cogl_perspective
cogl_frustum
cogl_setup_viewport
cogl_viewport
cogl_get_modelview_matrix
cogl_get_projection_matrix
cogl_get_viewport
<SUBSECTION>
cogl_push_matrix
cogl_pop_matrix
cogl_scale
cogl_translate
cogl_rotate
cogl_frustum
cogl_perspective
cogl_ortho
<SUBSECTION>
cogl_get_modelview_matrix
cogl_set_modelview_matrix
cogl_get_projection_matrix
cogl_set_projection_matrix
cogl_viewport
cogl_setup_viewport
cogl_get_viewport
<SUBSECTION>
cogl_clear
cogl_get_bitmasks