Applied 'final patch' from bug #874

* clutter/cogl/gles/cogl.c:
	* clutter/cogl/gl/cogl.c: The clip planes are now set using the
	inverse projection matrix as the modelview matrix so that they can
	be specified in screen coordinates.

	* clutter/cogl/gles/cogl-context.h (CoglContext):
	* clutter/cogl/gl/cogl-context.h (CoglContext): Added a member to
	cache the inverse projection matrix

	* clutter/clutter-fixed.h: Added a constant for converting from
	radians to degrees.

	* clutter/clutter-fixed.c (clutter_atani, clutter_atan2i): Added
	fixed-point versions of atan and atan2.

	* tests/test-clip.c: Added a test for clipping with various
	rotations and depths.

	* tests/Makefile.am (noinst_PROGRAMS): Added test-clip
This commit is contained in:
Neil Roberts 2008-06-02 12:34:10 +00:00
parent 165531074b
commit e306b0135c
4 changed files with 246 additions and 27 deletions

View File

@ -49,6 +49,9 @@ typedef struct
CoglFixedVec2 path_nodes_min;
CoglFixedVec2 path_nodes_max;
/* Cache of inverse projection matrix */
GLfloat inverse_projection[16];
/* Textures */
GArray *texture_handles;

137
gl/cogl.c
View File

@ -31,6 +31,7 @@
#include <string.h>
#include <gmodule.h>
#include <math.h>
#ifdef HAVE_CLUTTER_GLX
#include <dlfcn.h>
@ -385,6 +386,71 @@ cogl_color (const ClutterColor *color)
ctx->color_alpha = color->alpha;
}
static void
apply_matrix (const GLfloat *matrix, GLfloat *vertex)
{
int x, y;
GLfloat vertex_out[4] = { 0 };
for (y = 0; y < 4; y++)
for (x = 0; x < 4; x++)
vertex_out[y] += vertex[x] * matrix[y + x * 4];
memcpy (vertex, vertex_out, sizeof (vertex_out));
}
static void
project_vertex (GLfloat *modelview, GLfloat *project, GLfloat *vertex)
{
int i;
/* Apply the modelview matrix */
apply_matrix (modelview, vertex);
/* Apply the projection matrix */
apply_matrix (project, vertex);
/* Convert from homogenized coordinates */
for (i = 0; i < 4; i++)
vertex[i] /= vertex[3];
}
static void
set_clip_plane (GLint plane_num,
const GLfloat *vertex_a,
const GLfloat *vertex_b)
{
GLdouble plane[4];
GLfloat angle;
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
/* Calculate the angle between the axes and the line crossing the
two points */
angle = atan2f ((vertex_b[1] - vertex_a[1]),
(vertex_b[0] - vertex_a[0])) * 180.0f / M_PI;
GE( glPushMatrix () );
/* Load the identity matrix and multiply by the reverse of the
projection matrix so we can specify the plane in screen
coordinates */
GE( glLoadIdentity () );
GE( glMultMatrixf (ctx->inverse_projection) );
/* Rotate about point a */
GE( glTranslatef (vertex_a[0], vertex_a[1], vertex_a[2]) );
/* Rotate the plane by the calculated angle so that it will connect
the two points */
GE( glRotatef (angle, 0.0f, 0.0f, 1.0f) );
GE( glTranslatef (-vertex_a[0], -vertex_a[1], -vertex_a[2]) );
plane[0] = 0.0f;
plane[1] = -1.0f;
plane[2] = 0.0f;
plane[3] = vertex_a[1];
GE( glClipPlane (plane_num, plane) );
GE( glPopMatrix () );
GE( glEnable (plane_num) );
}
void
cogl_clip_set (ClutterFixed x_offset,
ClutterFixed y_offset,
@ -393,22 +459,50 @@ cogl_clip_set (ClutterFixed x_offset,
{
if (cogl_features_available (COGL_FEATURE_FOUR_CLIP_PLANES))
{
GLdouble eqn_left[4] = { 1.0, 0, 0,
-CLUTTER_FIXED_TO_FLOAT (x_offset) };
GLdouble eqn_right[4] = { -1.0, 0, 0,
CLUTTER_FIXED_TO_FLOAT (x_offset + width) };
GLdouble eqn_top[4] = { 0, 1.0, 0, -CLUTTER_FIXED_TO_FLOAT (y_offset) };
GLdouble eqn_bottom[4] = { 0, -1.0, 0, CLUTTER_FIXED_TO_FLOAT
(y_offset + height) };
GLfloat modelview[16], projection[16];
GE( glClipPlane (GL_CLIP_PLANE0, eqn_left) );
GE( glClipPlane (GL_CLIP_PLANE1, eqn_right) );
GE( glClipPlane (GL_CLIP_PLANE2, eqn_top) );
GE( glClipPlane (GL_CLIP_PLANE3, eqn_bottom) );
GE( glEnable (GL_CLIP_PLANE0) );
GE( glEnable (GL_CLIP_PLANE1) );
GE( glEnable (GL_CLIP_PLANE2) );
GE( glEnable (GL_CLIP_PLANE3) );
GLfloat vertex_tl[4] = { CLUTTER_FIXED_TO_FLOAT (x_offset),
CLUTTER_FIXED_TO_FLOAT (y_offset),
0.0f, 1.0f };
GLfloat vertex_tr[4] = { CLUTTER_FIXED_TO_FLOAT (x_offset + width),
CLUTTER_FIXED_TO_FLOAT (y_offset),
0.0f, 1.0f };
GLfloat vertex_bl[4] = { CLUTTER_FIXED_TO_FLOAT (x_offset),
CLUTTER_FIXED_TO_FLOAT (y_offset + height),
0.0f, 1.0f };
GLfloat vertex_br[4] = { CLUTTER_FIXED_TO_FLOAT (x_offset + width),
CLUTTER_FIXED_TO_FLOAT (y_offset + height),
0.0f, 1.0f };
GE( glGetFloatv (GL_MODELVIEW_MATRIX, modelview) );
GE( glGetFloatv (GL_PROJECTION_MATRIX, projection) );
project_vertex (modelview, projection, vertex_tl);
project_vertex (modelview, projection, vertex_tr);
project_vertex (modelview, projection, vertex_bl);
project_vertex (modelview, projection, vertex_br);
/* If the order of the top and bottom lines is different from
the order of the left and right lines then the clip rect must
have been transformed so that the back is visible. We
therefore need to swap one pair of vertices otherwise all of
the planes will be the wrong way around */
if ((vertex_tl[0] < vertex_tr[0] ? 1 : 0)
!= (vertex_bl[1] < vertex_tl[1] ? 1 : 0))
{
GLfloat temp[4];
memcpy (temp, vertex_tl, sizeof (temp));
memcpy (vertex_tl, vertex_tr, sizeof (temp));
memcpy (vertex_tr, temp, sizeof (temp));
memcpy (temp, vertex_bl, sizeof (temp));
memcpy (vertex_bl, vertex_br, sizeof (temp));
memcpy (vertex_br, temp, sizeof (temp));
}
set_clip_plane (GL_CLIP_PLANE0, vertex_tl, vertex_tr);
set_clip_plane (GL_CLIP_PLANE1, vertex_tr, vertex_br);
set_clip_plane (GL_CLIP_PLANE2, vertex_br, vertex_bl);
set_clip_plane (GL_CLIP_PLANE3, vertex_bl, vertex_tl);
}
else if (cogl_features_available (COGL_FEATURE_STENCIL_BUFFER))
{
@ -467,6 +561,8 @@ cogl_perspective (ClutterFixed fovy,
GLfloat m[16];
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
memset (&m[0], 0, sizeof (m));
/*
@ -495,6 +591,17 @@ cogl_perspective (ClutterFixed fovy,
M(3,2) = -1.0F;
GE( glMultMatrixf (m) );
/* Calculate and store the inverse of the matrix */
memset (ctx->inverse_projection, 0, sizeof (GLfloat) * 16);
#define m ctx->inverse_projection
M(0, 0) = 1.0f / CLUTTER_FIXED_TO_FLOAT (x);
M(1, 1) = 1.0f / CLUTTER_FIXED_TO_FLOAT (y);
M(2, 3) = -1.0f;
M(3, 2) = 1.0f / CLUTTER_FIXED_TO_FLOAT (d);
M(3, 3) = CLUTTER_FIXED_TO_FLOAT (c) / CLUTTER_FIXED_TO_FLOAT (d);
#undef m
#undef M
}

View File

@ -58,6 +58,9 @@ typedef struct
CoglFixedVec2 path_nodes_min;
CoglFixedVec2 path_nodes_max;
/* Cache of inverse projection matrix */
ClutterFixed inverse_projection[16];
/* Textures */
GArray *texture_handles;
CoglTextureGLVertex *texture_vertices;

View File

@ -312,6 +312,74 @@ cogl_color (const ClutterColor *color)
ctx->color_alpha = color->alpha;
}
static void
apply_matrix (const ClutterFixed *matrix, ClutterFixed *vertex)
{
int x, y;
ClutterFixed vertex_out[4] = { 0 };
for (y = 0; y < 4; y++)
for (x = 0; x < 4; x++)
vertex_out[y] += CFX_QMUL (vertex[x], matrix[y + x * 4]);
memcpy (vertex, vertex_out, sizeof (vertex_out));
}
static void
project_vertex (ClutterFixed *modelview,
ClutterFixed *project,
ClutterFixed *vertex)
{
int i;
/* Apply the modelview matrix */
apply_matrix (modelview, vertex);
/* Apply the projection matrix */
apply_matrix (project, vertex);
/* Convert from homogenized coordinates */
for (i = 0; i < 4; i++)
vertex[i] = CFX_QDIV (vertex[i], vertex[3]);
}
static void
set_clip_plane (GLint plane_num,
const ClutterFixed *vertex_a,
const ClutterFixed *vertex_b)
{
GLfixed plane[4];
GLfixed angle;
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
/* Calculate the angle between the axes and the line crossing the
two points */
angle = CFX_QMUL (clutter_atan2i (vertex_b[1] - vertex_a[1],
vertex_b[0] - vertex_a[0]),
CFX_RADIANS_TO_DEGREES);
GE( cogl_wrap_glPushMatrix () );
/* Load the identity matrix and multiply by the reverse of the
projection matrix so we can specify the plane in screen
coordinates */
GE( cogl_wrap_glLoadIdentity () );
GE( cogl_wrap_glMultMatrixx ((GLfixed *) ctx->inverse_projection) );
/* Rotate about point a */
GE( cogl_wrap_glTranslatex (vertex_a[0], vertex_a[1], vertex_a[2]) );
/* Rotate the plane by the calculated angle so that it will connect
the two points */
GE( cogl_wrap_glRotatex (angle, 0.0f, 0.0f, 1.0f) );
GE( cogl_wrap_glTranslatex (-vertex_a[0], -vertex_a[1], -vertex_a[2]) );
plane[0] = 0;
plane[1] = -CFX_ONE;
plane[2] = 0;
plane[3] = vertex_a[1];
GE( cogl_wrap_glClipPlanex (plane_num, plane) );
GE( cogl_wrap_glPopMatrix () );
GE( cogl_wrap_glEnable (plane_num) );
}
void
cogl_clip_set (ClutterFixed x_offset,
ClutterFixed y_offset,
@ -320,19 +388,43 @@ cogl_clip_set (ClutterFixed x_offset,
{
if (cogl_features_available (COGL_FEATURE_FOUR_CLIP_PLANES))
{
GLfixed eqn_left[4] = { CFX_ONE, 0, 0, -x_offset };
GLfixed eqn_right[4] = { -CFX_ONE, 0, 0, x_offset + width };
GLfixed eqn_top[4] = { 0, CFX_ONE, 0, -y_offset };
GLfixed eqn_bottom[4] = { 0, -CFX_ONE, 0, y_offset + height };
GLfixed modelview[16], projection[16];
GE( cogl_wrap_glClipPlanex (GL_CLIP_PLANE0, eqn_left) );
GE( cogl_wrap_glClipPlanex (GL_CLIP_PLANE1, eqn_right) );
GE( cogl_wrap_glClipPlanex (GL_CLIP_PLANE2, eqn_top) );
GE( cogl_wrap_glClipPlanex (GL_CLIP_PLANE3, eqn_bottom) );
GE( cogl_wrap_glEnable (GL_CLIP_PLANE0) );
GE( cogl_wrap_glEnable (GL_CLIP_PLANE1) );
GE( cogl_wrap_glEnable (GL_CLIP_PLANE2) );
GE( cogl_wrap_glEnable (GL_CLIP_PLANE3) );
ClutterFixed vertex_tl[4] = { x_offset, y_offset, 0, CFX_ONE };
ClutterFixed vertex_tr[4] = { x_offset + width, y_offset, 0, CFX_ONE };
ClutterFixed vertex_bl[4] = { x_offset, y_offset + height, 0, CFX_ONE };
ClutterFixed vertex_br[4] = { x_offset + width, y_offset + height,
0, CFX_ONE };
GE( cogl_wrap_glGetFixedv (GL_MODELVIEW_MATRIX, modelview) );
GE( cogl_wrap_glGetFixedv (GL_PROJECTION_MATRIX, projection) );
project_vertex (modelview, projection, vertex_tl);
project_vertex (modelview, projection, vertex_tr);
project_vertex (modelview, projection, vertex_bl);
project_vertex (modelview, projection, vertex_br);
/* If the order of the top and bottom lines is different from
the order of the left and right lines then the clip rect must
have been transformed so that the back is visible. We
therefore need to swap one pair of vertices otherwise all of
the planes will be the wrong way around */
if ((vertex_tl[0] < vertex_tr[0] ? 1 : 0)
!= (vertex_bl[1] < vertex_tl[1] ? 1 : 0))
{
ClutterFixed temp[4];
memcpy (temp, vertex_tl, sizeof (temp));
memcpy (vertex_tl, vertex_tr, sizeof (temp));
memcpy (vertex_tr, temp, sizeof (temp));
memcpy (temp, vertex_bl, sizeof (temp));
memcpy (vertex_bl, vertex_br, sizeof (temp));
memcpy (vertex_br, temp, sizeof (temp));
}
set_clip_plane (GL_CLIP_PLANE0, vertex_tl, vertex_tr);
set_clip_plane (GL_CLIP_PLANE1, vertex_tr, vertex_br);
set_clip_plane (GL_CLIP_PLANE2, vertex_br, vertex_bl);
set_clip_plane (GL_CLIP_PLANE3, vertex_bl, vertex_tl);
}
else if (cogl_features_available (COGL_FEATURE_STENCIL_BUFFER))
{
@ -391,6 +483,8 @@ cogl_perspective (ClutterFixed fovy,
GLfixed m[16];
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
memset (&m[0], 0, sizeof (m));
/*
@ -419,6 +513,18 @@ cogl_perspective (ClutterFixed fovy,
M(3,2) = 1 + ~CFX_ONE;
GE( cogl_wrap_glMultMatrixx (m) );
/* Calculate and store the inverse of the matrix */
memset (ctx->inverse_projection, 0, sizeof (ClutterFixed) * 16);
#define m ctx->inverse_projection
M(0, 0) = CFX_QDIV (CFX_ONE, x);
M(1, 1) = CFX_QDIV (CFX_ONE, y);
M(2, 3) = -CFX_ONE;
M(3, 2) = CFX_QDIV (CFX_ONE, d);
M(3, 3) = CFX_QDIV (c, d);
#undef m
#undef M
}