Bug 945 - Clipping+fbo cloning bugs

* clutter/cogl/gl/cogl.c: 
	* clutter/cogl/gles/cogl.c: 
	* clutter/cogl/cogl.h.in: Add cogl_clip_stack_save,
	cogl_clip_stack_restore, cogl_viewport and cogl_frustum.

	* clutter/cogl/gl/cogl-fbo.h: 
	* clutter/cogl/gl/cogl-fbo.c: Try to attach a stencil buffer when
	creating an FBO.

	* clutter/cogl/common/cogl-clip-stack.c: Add functions to save and
	restore the whole state of the stack.

	* clutter/clutter-texture.c (clutter_texture_paint): When
	rendering the FBO source, setup a temporary asymmetric perspective
	projection matrix to render it as it would appear on screen.

	* clutter/clutter-private.h: 
	* clutter/clutter-actor.c
	(_clutter_actor_apply_modelview_transform_recursive): No longer
	static and exported in clutter-private.h
This commit is contained in:
Neil Roberts 2008-08-01 12:23:57 +00:00
parent fc73b84002
commit db4c5e2829
15 changed files with 449 additions and 39 deletions

View File

@ -1,3 +1,28 @@
2008-08-01 Neil Roberts <neil@o-hand.com>
Bug 945 - Clipping+fbo cloning bugs
* clutter/cogl/gl/cogl.c:
* clutter/cogl/gles/cogl.c:
* clutter/cogl/cogl.h.in: Add cogl_clip_stack_save,
cogl_clip_stack_restore, cogl_viewport and cogl_frustum.
* clutter/cogl/gl/cogl-fbo.h:
* clutter/cogl/gl/cogl-fbo.c: Try to attach a stencil buffer when
creating an FBO.
* clutter/cogl/common/cogl-clip-stack.c: Add functions to save and
restore the whole state of the stack.
* clutter/clutter-texture.c (clutter_texture_paint): When
rendering the FBO source, setup a temporary asymmetric perspective
projection matrix to render it as it would appear on screen.
* clutter/clutter-private.h:
* clutter/clutter-actor.c
(_clutter_actor_apply_modelview_transform_recursive): No longer
static and exported in clutter-private.h
2008-08-01 Neil Roberts <neil@o-hand.com>
Bug 1071 - clutter_timeline_get_duration doesn't always work

View File

@ -362,8 +362,6 @@ static guint actor_signals[LAST_SIGNAL] = { 0, };
static void clutter_scriptable_iface_init (ClutterScriptableIface *iface);
static void _clutter_actor_apply_modelview_transform (ClutterActor *self);
static void _clutter_actor_apply_modelview_transform_recursive (ClutterActor *self,
ClutterActor *ancestor);
static void clutter_actor_shader_pre_paint (ClutterActor *actor,
gboolean repeat);
@ -1373,7 +1371,7 @@ _clutter_actor_apply_modelview_transform (ClutterActor *self)
* This function does not push/pop matrix; it is the responsibility
* of the caller to do so as appropriate
*/
static void
void
_clutter_actor_apply_modelview_transform_recursive (ClutterActor *self,
ClutterActor *ancestor)
{

View File

@ -210,6 +210,9 @@ gboolean _clutter_boolean_handled_accumulator (GSignalInvocationHint *ihint,
const GValue *handler_return,
gpointer dummy);
void _clutter_actor_apply_modelview_transform_recursive (ClutterActor *self,
ClutterActor *ancestor);
G_END_DECLS
#endif /* _HAVE_CLUTTER_PRIVATE_H */

View File

@ -430,6 +430,62 @@ clutter_texture_allocate (ClutterActor *self,
clutter_actor_allocate_preferred_size (priv->fbo_source, origin_changed);
}
static void
clutter_texture_set_fbo_projection (ClutterActor *self)
{
ClutterTexturePrivate *priv = CLUTTER_TEXTURE (self)->priv;
ClutterVertex verts[4];
ClutterFixed viewport[4];
ClutterFixed x_min, x_max, y_min, y_max;
ClutterPerspective perspective;
ClutterStage *stage;
ClutterFixed tan_angle, near_size;
int i;
/* Get the bounding rectangle of the source as drawn in screen
coordinates */
clutter_actor_get_abs_allocation_vertices (priv->fbo_source, verts);
x_min = x_max = verts[0].x;
y_min = y_max = verts[0].y;
for (i = 1; i < G_N_ELEMENTS (verts); ++i)
{
if (verts[i].x < x_min)
x_min = verts[i].x;
if (verts[i].x > x_max)
x_max = verts[i].x;
if (verts[i].y < y_min)
y_min = verts[i].y;
if (verts[i].y > y_max)
y_max = verts[i].y;
}
stage = CLUTTER_STAGE (clutter_actor_get_stage (self));
clutter_stage_get_perspectivex (stage, &perspective);
/* Convert the coordinates back to [-1,1] range */
cogl_get_viewport (viewport);
x_min = CFX_QDIV (x_min, viewport[2]) * 2 - CFX_ONE;
x_max = CFX_QDIV (x_max, viewport[2]) * 2 - CFX_ONE;
y_min = CFX_QDIV (y_min, viewport[3]) * 2 - CFX_ONE;
y_max = CFX_QDIV (y_max, viewport[3]) * 2 - CFX_ONE;
/* Set up a projection matrix so that the actor will be projected as
if it was drawn at its original location */
tan_angle = clutter_tani (CLUTTER_ANGLE_FROM_DEGX (perspective.fovy / 2));
near_size = CFX_QMUL (perspective.z_near, tan_angle);
cogl_frustum (CFX_QMUL (x_min, near_size),
CFX_QMUL (x_max, near_size),
CFX_QMUL (-y_min, near_size),
CFX_QMUL (-y_max, near_size),
perspective.z_near, perspective.z_far);
}
static void
clutter_texture_paint (ClutterActor *self)
{
@ -447,6 +503,8 @@ clutter_texture_paint (ClutterActor *self)
{
ClutterMainContext *context;
ClutterShader *shader = NULL;
ClutterActor *stage = NULL;
ClutterPerspective perspective;
context = clutter_context_get_default ();
@ -462,15 +520,52 @@ clutter_texture_paint (ClutterActor *self)
/* Redirect drawing to the fbo */
cogl_draw_buffer (COGL_OFFSCREEN_BUFFER, priv->fbo_handle);
if ((stage = clutter_actor_get_stage (self)))
{
guint stage_width, stage_height;
ClutterActor *source_parent;
clutter_stage_get_perspectivex (CLUTTER_STAGE (stage), &perspective);
clutter_actor_get_size (stage, &stage_width, &stage_height);
/* Use below to set the modelview matrix as if the viewport
was still the same size as the stage */
cogl_setup_viewport (stage_width, stage_height,
perspective.fovy,
perspective.aspect,
perspective.z_near,
perspective.z_far);
/* Use a projection matrix that makes the actor appear as it
would if it was rendered at its normal screen location */
clutter_texture_set_fbo_projection (self);
/* Reset the viewport to the size of the FBO */
cogl_viewport (priv->width, priv->height);
/* Reapply the source's parent transformations */
if ((source_parent = clutter_actor_get_parent (priv->fbo_source)))
_clutter_actor_apply_modelview_transform_recursive (source_parent,
NULL);
}
/* cogl_paint_init is called to clear the buffers */
cogl_paint_init (&transparent_col);
/* Clear the clipping stack so that if the FBO actor is being
clipped then it won't affect drawing the source */
cogl_clip_stack_save ();
/* Render out actor scene to fbo */
clutter_actor_paint (priv->fbo_source);
cogl_clip_stack_restore ();
/* Restore drawing to the frame buffer */
cogl_draw_buffer (COGL_WINDOW_BUFFER, COGL_INVALID_HANDLE);
/* Restore the perspective matrix using cogl_perspective so that
the inverse matrix will be right */
cogl_perspective (perspective.fovy, perspective.aspect,
perspective.z_near, perspective.z_far);
/* If there is a shader on top of the shader stack, turn it back on. */
if (shader)
clutter_shader_set_is_enabled (shader, TRUE);
@ -1600,13 +1695,13 @@ on_fbo_source_size_change (GObject *object,
priv->width = w;
priv->height = h;
priv->texture = cogl_texture_new_with_size (priv->width,
priv->height,
priv->texture = cogl_texture_new_with_size (MAX (priv->width, 1),
MAX (priv->height, 1),
-1,
priv->filter_quality == CLUTTER_TEXTURE_QUALITY_HIGH,
COGL_PIXEL_FORMAT_RGBA_8888);
cogl_texture_set_filters (priv->texture,
cogl_texture_set_filters (priv->texture,
clutter_texture_quality_to_cogl_min_filter (priv->filter_quality),
clutter_texture_quality_to_cogl_mag_filter (priv->filter_quality));
@ -1673,6 +1768,21 @@ on_fbo_parent_change (ClutterActor *actor,
* adding it to a container.</para>
* </listitem>
* <listitem>
* <para>When getting the image for the clone texture, Clutter
* will attempt to render the source actor exactly as it would
* appear if it was rendered on screen. The source actor's parent
* transformations are taken into account. Therefore if your
* source actor is rotated along the X or Y axes so that it has
* some depth, the texture will appear differently depending on
* the on-screen location of the source actor. While painting the
* source actor, Clutter will set up a temporary asymmetric
* perspective matrix as the projection matrix so that the source
* actor will be projected as if a small section of the screen was
* being viewed. Before version 0.8.2, an orthogonal identity
* projection was used which meant that the source actor would be
* clipped if any part of it was not on the zero Z-plane.</para>
* </listitem>
* <listitem>
* <para>Avoid reparenting the source with the created texture.</para>
* </listitem>
* <listitem>

View File

@ -338,14 +338,35 @@ void cogl_get_bitmasks (gint *red,
* @z_near: Nearest visible point
* @z_far: Furthest visible point along the z-axis
*
* Multiplies the current set matrix with a projection matrix based
* on the provided values.
* Replaces the current projection matrix with a perspective matrix
* based on the provided values.
*/
void cogl_perspective (ClutterFixed fovy,
ClutterFixed aspect,
ClutterFixed z_near,
ClutterFixed z_far);
/**
* cogl_frustum:
* @left: Left clipping plane
* @right: Right clipping plane
* @bottom: Bottom clipping plane
* @top: Top clipping plane
* @z_near: Nearest visible point
* @z_far: Furthest visible point along the z-axis
*
* Replaces the current projection matrix with a perspective matrix
* for the given viewing frustum.
*
* Since: 0.8.2
*/
void cogl_frustum (ClutterFixed left,
ClutterFixed right,
ClutterFixed bottom,
ClutterFixed top,
ClutterFixed z_near,
ClutterFixed z_far);
/**
* cogl_setup_viewport:
* @width: Width of the viewport
@ -369,6 +390,18 @@ void cogl_setup_viewport (guint width,
ClutterFixed z_near,
ClutterFixed z_far);
/**
* cogl_viewport:
* @width: Width of the viewport
* @height: Height of the viewport
*
* Replace the current viewport with the given values.
*
* Since: 0.8.2
*/
void cogl_viewport (guint width,
guint height);
/**
* cogl_push_matrix:
*
@ -511,6 +544,29 @@ void cogl_clip_set (ClutterFixed x_offset,
*/
void cogl_clip_unset (void);
/**
* cogl_clip_stack_save:
*
* Save the entire state of the clipping stack and then clear all
* clipping. The previous state can be returned to with
* cogl_clip_stack_restore(). Each call to cogl_clip_set() after this
* must be matched by a call to cogl_clip_unset() before calling
* cogl_clip_stack_restore().
*
* Since: 0.8.2
*/
void cogl_clip_stack_save (void);
/**
* cogl_clip_stack_restore:
*
* Restore the state of the clipping stack that was previously saved
* by cogl_clip_stack_save().
*
* Since: 0.8.2
*/
void cogl_clip_stack_restore (void);
/**
* cogl_enable_depth_test:
* @setting: %TRUE to enable depth testing or %FALSE to disable.

View File

@ -50,6 +50,12 @@ typedef struct _CoglClipStackEntry CoglClipStackEntry;
struct _CoglClipStackEntry
{
/* If this is set then this entry clears the clip stack. This is
used to clear the stack when drawing an FBO put to keep the
entries so they can be restored when the FBO drawing is
completed */
gboolean clear;
/* The rectangle for this clip */
ClutterFixed x_offset;
ClutterFixed y_offset;
@ -61,7 +67,6 @@ struct _CoglClipStackEntry
};
static GList *cogl_clip_stack_top = NULL;
static GList *cogl_clip_stack_bottom = NULL;
static int cogl_clip_stack_depth = 0;
static void
@ -93,6 +98,7 @@ cogl_clip_set (ClutterFixed x_offset,
CoglClipStackEntry *entry = g_slice_new (CoglClipStackEntry);
/* Make a new entry */
entry->clear = FALSE;
entry->x_offset = x_offset;
entry->y_offset = y_offset;
entry->width = width;
@ -105,8 +111,6 @@ cogl_clip_set (ClutterFixed x_offset,
/* Store it in the stack */
cogl_clip_stack_top = g_list_prepend (cogl_clip_stack_top, entry);
if (cogl_clip_stack_bottom == NULL)
cogl_clip_stack_bottom = cogl_clip_stack_top;
}
void
@ -118,8 +122,6 @@ cogl_clip_unset (void)
g_slice_free (CoglClipStackEntry, cogl_clip_stack_top->data);
cogl_clip_stack_top = g_list_delete_link (cogl_clip_stack_top,
cogl_clip_stack_top);
if (cogl_clip_stack_top == NULL)
cogl_clip_stack_bottom = NULL;
cogl_clip_stack_depth--;
/* Rebuild the clip */
@ -131,7 +133,7 @@ _cogl_clip_stack_rebuild (gboolean just_stencil)
{
int has_clip_planes = cogl_features_available (COGL_FEATURE_FOUR_CLIP_PLANES);
GList *node;
int depth = 1;
int depth = 0;
/* Disable clip planes if the stack is empty */
if (has_clip_planes && cogl_clip_stack_depth < 1)
@ -141,8 +143,14 @@ _cogl_clip_stack_rebuild (gboolean just_stencil)
if (cogl_clip_stack_depth < (has_clip_planes ? 2 : 1))
_cogl_disable_stencil_buffer ();
/* Find the bottom of the stack */
for (node = cogl_clip_stack_top; depth < cogl_clip_stack_depth - 1;
node = node->next)
depth++;
/* Re-add every entry from the bottom of the stack up */
for (node = cogl_clip_stack_bottom; node; node = node->prev, depth++)
depth = 1;
for (; depth <= cogl_clip_stack_depth; node = node->prev, depth++)
if (!just_stencil || !has_clip_planes || depth > 1)
{
const CoglClipStackEntry *entry = (CoglClipStackEntry *) node->data;
@ -156,12 +164,16 @@ _cogl_clip_stack_rebuild (gboolean just_stencil)
void
_cogl_clip_stack_merge (void)
{
GList *node = cogl_clip_stack_bottom;
GList *node = cogl_clip_stack_top;
int i;
/* Merge the current clip stack on top of whatever is in the stencil
buffer */
if (node)
if (cogl_clip_stack_depth)
{
for (i = 0; i < cogl_clip_stack_depth - 1; i++)
node = node->next;
/* Skip the first entry if we have clipping planes */
if (cogl_features_available (COGL_FEATURE_FOUR_CLIP_PLANES))
node = node->prev;
@ -178,3 +190,43 @@ _cogl_clip_stack_merge (void)
}
}
}
void
cogl_clip_stack_save (void)
{
CoglClipStackEntry *entry = g_slice_new (CoglClipStackEntry);
/* Push an entry into the stack to mark that it should be cleared */
entry->clear = TRUE;
cogl_clip_stack_top = g_list_prepend (cogl_clip_stack_top, entry);
/* Reset the depth to zero */
cogl_clip_stack_depth = 0;
/* Rebuilding the stack will now disabling all clipping */
_cogl_clip_stack_rebuild (FALSE);
}
void
cogl_clip_stack_restore (void)
{
GList *node;
/* The top of the stack should be a clear marker */
g_assert (cogl_clip_stack_top);
g_assert (((CoglClipStackEntry *) cogl_clip_stack_top->data)->clear);
/* Remove the top entry */
g_slice_free (CoglClipStackEntry, cogl_clip_stack_top->data);
cogl_clip_stack_top = g_list_delete_link (cogl_clip_stack_top,
cogl_clip_stack_top);
/* Recalculate the depth of the stack */
cogl_clip_stack_depth = 0;
for (node = cogl_clip_stack_top;
node && !((CoglClipStackEntry *) node->data)->clear;
node = node->next)
cogl_clip_stack_depth++;
_cogl_clip_stack_rebuild (FALSE);
}

View File

@ -26,11 +26,6 @@
#ifndef __COGL_CLIP_STACK_H
#define __COGL_CLIP_STACK_H
void cogl_clip_set (ClutterFixed x_offset,
ClutterFixed y_offset,
ClutterFixed width,
ClutterFixed height);
void cogl_clip_unset (void);
void _cogl_clip_stack_rebuild (gboolean just_stencil);
void _cogl_clip_stack_merge (void);

View File

@ -68,6 +68,7 @@ typedef struct
/* Relying on glext.h to define these */
COGL_PFNGLGENRENDERBUFFERSEXTPROC pf_glGenRenderbuffersEXT;
COGL_PFNGLDELETERENDERBUFFERSEXTPROC pf_glDeleteRenderbuffersEXT;
COGL_PFNGLBINDRENDERBUFFEREXTPROC pf_glBindRenderbufferEXT;
COGL_PFNGLRENDERBUFFERSTORAGEEXTPROC pf_glRenderbufferStorageEXT;
COGL_PFNGLGENFRAMEBUFFERSEXTPROC pf_glGenFramebuffersEXT;

View File

@ -37,6 +37,7 @@
/* Expecting EXT functions not to be defined - redirect to pointers in context */
#define glGenRenderbuffersEXT ctx->pf_glGenRenderbuffersEXT
#define glDeleteRenderbuffersEXT ctx->pf_glDeleteRenderbuffersEXT
#define glBindRenderbufferEXT ctx->pf_glBindRenderbufferEXT
#define glRenderbufferStorageEXT ctx->pf_glRenderbufferStorageEXT
#define glGenFramebuffersEXT ctx->pf_glGenFramebuffersEXT
@ -68,6 +69,7 @@ cogl_offscreen_new_to_texture (CoglHandle texhandle)
CoglTexSliceSpan *y_span;
GLuint tex_gl_handle;
GLuint fbo_gl_handle;
GLuint gl_stencil_handle;
GLenum status;
_COGL_GET_CONTEXT (ctx, COGL_INVALID_HANDLE);
@ -92,21 +94,47 @@ cogl_offscreen_new_to_texture (CoglHandle texhandle)
x_span = &g_array_index (tex->slice_x_spans, CoglTexSliceSpan, 0);
y_span = &g_array_index (tex->slice_y_spans, CoglTexSliceSpan, 0);
tex_gl_handle = g_array_index (tex->slice_gl_handles, GLuint, 0);
/* Create a renderbuffer for stenciling */
GE( glGenRenderbuffersEXT (1, &gl_stencil_handle) );
GE( glBindRenderbufferEXT (GL_RENDERBUFFER_EXT, gl_stencil_handle) );
GE( glRenderbufferStorageEXT (GL_RENDERBUFFER_EXT, GL_STENCIL_INDEX8_EXT,
cogl_texture_get_width (texhandle),
cogl_texture_get_height (texhandle)) );
GE( glBindRenderbufferEXT (GL_RENDERBUFFER_EXT, 0) );
/* Generate framebuffer */
glGenFramebuffersEXT (1, &fbo_gl_handle);
GE( glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, fbo_gl_handle) );
GE( glFramebufferTexture2DEXT (GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
tex->gl_target, tex_gl_handle, 0) );
GE( glFramebufferRenderbufferEXT (GL_FRAMEBUFFER_EXT,
GL_STENCIL_ATTACHMENT_EXT,
GL_RENDERBUFFER_EXT, gl_stencil_handle) );
/* Make sure it's complete */
status = glCheckFramebufferStatusEXT (GL_FRAMEBUFFER_EXT);
if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
{
GE( glDeleteFramebuffersEXT (1, &fbo_gl_handle) );
GE( glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, 0) );
return COGL_INVALID_HANDLE;
/* Stencil renderbuffers aren't always supported. Try again
without the stencil buffer */
GE( glFramebufferRenderbufferEXT (GL_FRAMEBUFFER_EXT,
GL_STENCIL_ATTACHMENT_EXT,
GL_RENDERBUFFER_EXT,
0) );
GE( glDeleteRenderbuffersEXT (1, &gl_stencil_handle) );
gl_stencil_handle = 0;
status = glCheckFramebufferStatusEXT (GL_FRAMEBUFFER_EXT);
if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
{
/* Still failing, so give up */
GE( glDeleteFramebuffersEXT (1, &fbo_gl_handle) );
GE( glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, 0) );
return COGL_INVALID_HANDLE;
}
}
GE( glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, 0) );
@ -114,10 +142,11 @@ cogl_offscreen_new_to_texture (CoglHandle texhandle)
/* Allocate and init a CoglFbo object (store non-wasted size
for subsequent blits and viewport setup) */
fbo = (CoglFbo*) g_malloc (sizeof (CoglFbo));
fbo->ref_count = 1;
fbo->width = x_span->size - x_span->waste;
fbo->height = y_span->size - y_span->waste;
fbo->gl_handle = fbo_gl_handle;
fbo->ref_count = 1;
fbo->width = x_span->size - x_span->waste;
fbo->height = y_span->size - y_span->waste;
fbo->gl_handle = fbo_gl_handle;
fbo->gl_stencil_handle = gl_stencil_handle;
COGL_HANDLE_DEBUG_NEW (offscreen, fbo);
@ -140,7 +169,8 @@ _cogl_offscreen_free (CoglFbo *fbo)
/* Frees FBO resources but its handle is not
released! Do that separately before this! */
if (fbo->gl_stencil_handle)
GE( glDeleteRenderbuffersEXT (1, &fbo->gl_stencil_handle) );
GE( glDeleteFramebuffersEXT (1, &fbo->gl_handle) );
g_free (fbo);
}

View File

@ -32,6 +32,7 @@ typedef struct
int width;
int height;
GLuint gl_handle;
GLuint gl_stencil_handle;
} CoglFbo;

View File

@ -746,6 +746,9 @@ cogl_perspective (ClutterFixed fovy,
memset (&m[0], 0, sizeof (m));
GE( glMatrixMode (GL_PROJECTION) );
GE( glLoadIdentity () );
/*
* Based on the original algorithm in perspective():
*
@ -773,6 +776,8 @@ cogl_perspective (ClutterFixed fovy,
GE( glMultMatrixf (m) );
GE( glMatrixMode (GL_MODELVIEW) );
/* Calculate and store the inverse of the matrix */
memset (ctx->inverse_projection, 0, sizeof (GLfloat) * 16);
@ -786,6 +791,60 @@ cogl_perspective (ClutterFixed fovy,
#undef M
}
void
cogl_frustum (ClutterFixed left,
ClutterFixed right,
ClutterFixed bottom,
ClutterFixed top,
ClutterFixed z_near,
ClutterFixed z_far)
{
GLfloat c, d;
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
GE( glMatrixMode (GL_PROJECTION) );
GE( glLoadIdentity () );
GE( glFrustum (CLUTTER_FIXED_TO_DOUBLE (left),
CLUTTER_FIXED_TO_DOUBLE (right),
CLUTTER_FIXED_TO_DOUBLE (bottom),
CLUTTER_FIXED_TO_DOUBLE (top),
CLUTTER_FIXED_TO_DOUBLE (z_near),
CLUTTER_FIXED_TO_DOUBLE (z_far)) );
GE( glMatrixMode (GL_MODELVIEW) );
/* Calculate and store the inverse of the matrix */
memset (ctx->inverse_projection, 0, sizeof (GLfloat) * 16);
c = -CLUTTER_FIXED_TO_FLOAT (z_far + z_near)
/ CLUTTER_FIXED_TO_FLOAT (z_far - z_near);
d = -CLUTTER_FIXED_TO_FLOAT (2 * CFX_QMUL (z_far, z_near))
/ CLUTTER_FIXED_TO_FLOAT (z_far - z_near);
#define M(row,col) ctx->inverse_projection[col*4+row]
M(0,0) = CLUTTER_FIXED_TO_FLOAT (right - left)
/ CLUTTER_FIXED_TO_FLOAT (2 * z_near);
M(0,3) = CLUTTER_FIXED_TO_FLOAT (right + left)
/ CLUTTER_FIXED_TO_FLOAT (2 * z_near);
M(1,1) = CLUTTER_FIXED_TO_FLOAT (top - bottom)
/ CLUTTER_FIXED_TO_FLOAT (2 * z_near);
M(1,3) = CLUTTER_FIXED_TO_FLOAT (top + bottom)
/ CLUTTER_FIXED_TO_FLOAT (2 * z_near);
M(2,3) = -1.0f;
M(3,2) = 1.0f / d;
M(3,3) = c / d;
#undef M
}
void
cogl_viewport (guint width,
guint height)
{
GE( glViewport (0, 0, width, height) );
}
void
cogl_setup_viewport (guint width,
guint height,
@ -798,12 +857,8 @@ cogl_setup_viewport (guint width,
GE( glViewport (0, 0, width, height) );
GE( glMatrixMode (GL_PROJECTION) );
GE( glLoadIdentity () );
cogl_perspective (fovy, aspect, z_near, z_far);
GE( glMatrixMode (GL_MODELVIEW) );
GE( glLoadIdentity () );
/*
@ -969,6 +1024,10 @@ _cogl_features_init ()
(COGL_PFNGLGENRENDERBUFFERSEXTPROC)
cogl_get_proc_address ("glGenRenderbuffersEXT");
ctx->pf_glDeleteRenderbuffersEXT =
(COGL_PFNGLDELETERENDERBUFFERSEXTPROC)
cogl_get_proc_address ("glDeleteRenderbuffersEXT");
ctx->pf_glBindRenderbufferEXT =
(COGL_PFNGLBINDRENDERBUFFEREXTPROC)
cogl_get_proc_address ("glBindRenderbufferEXT");

View File

@ -666,6 +666,31 @@ cogl_wrap_glMultMatrixx (const GLfixed *m)
cogl_wrap_glMultMatrix (new_matrix);
}
void
cogl_wrap_glFrustumx (GLfixed left, GLfixed right,
GLfixed bottom, GLfixed top,
GLfixed z_near, GLfixed z_far)
{
float matrix[16];
float two_near = CLUTTER_FIXED_TO_FLOAT (2 * z_near);
memset (matrix, 0, sizeof (matrix));
matrix[0] = two_near / CLUTTER_FIXED_TO_FLOAT (right - left);
matrix[5] = two_near / CLUTTER_FIXED_TO_FLOAT (top - bottom);
matrix[8] = CLUTTER_FIXED_TO_FLOAT (right + left)
/ CLUTTER_FIXED_TO_FLOAT (right - left);
matrix[9] = CLUTTER_FIXED_TO_FLOAT (top + bottom)
/ CLUTTER_FIXED_TO_FLOAT (top - bottom);
matrix[10] = -CLUTTER_FIXED_TO_FLOAT (z_far + z_near)
/ CLUTTER_FIXED_TO_FLOAT (z_far - z_near);
matrix[11] = -1.0f;
matrix[14] = -two_near * CLUTTER_FIXED_TO_FLOAT (z_far)
/ CLUTTER_FIXED_TO_FLOAT (z_far - z_near);
cogl_wrap_glMultMatrix (matrix);
}
void
cogl_wrap_glScalex (GLfixed x, GLfixed y, GLfixed z)
{

View File

@ -204,6 +204,9 @@ void cogl_wrap_glPopMatrix ();
void cogl_wrap_glMatrixMode (GLenum mode);
void cogl_wrap_glLoadIdentity ();
void cogl_wrap_glMultMatrixx (const GLfixed *m);
void cogl_wrap_glFrustumx (GLfixed left, GLfixed right,
GLfixed bottom, GLfixed top,
GLfixed z_near, GLfixed z_far);
void cogl_wrap_glScalex (GLfixed x, GLfixed y, GLfixed z);
void cogl_wrap_glTranslatex (GLfixed x, GLfixed y, GLfixed z);
void cogl_wrap_glRotatex (GLfixed angle, GLfixed x, GLfixed y, GLfixed z);
@ -268,6 +271,7 @@ void _cogl_gles2_clear_cache_for_program (CoglHandle program);
#define cogl_wrap_glMatrixMode glMatrixMode
#define cogl_wrap_glLoadIdentity glLoadIdentity
#define cogl_wrap_glMultMatrixx glMultMatrixx
#define cogl_wrap_glFrustumx glFrustumx
#define cogl_wrap_glScalex glScalex
#define cogl_wrap_glTranslatex glTranslatex
#define cogl_wrap_glRotatex glRotatex

View File

@ -661,7 +661,10 @@ cogl_perspective (ClutterFixed fovy,
memset (&m[0], 0, sizeof (m));
/*
GE( cogl_wrap_glMatrixMode (GL_PROJECTION) );
GE( cogl_wrap_glLoadIdentity () );
/*
* Based on the original algorithm in perspective():
*
* 1) xmin = -xmax => xmax + xmin == 0 && xmax - xmin == 2 * xmax
@ -688,6 +691,8 @@ cogl_perspective (ClutterFixed fovy,
GE( cogl_wrap_glMultMatrixx (m) );
GE( cogl_wrap_glMatrixMode (GL_MODELVIEW) );
/* Calculate and store the inverse of the matrix */
memset (ctx->inverse_projection, 0, sizeof (ClutterFixed) * 16);
@ -702,6 +707,51 @@ cogl_perspective (ClutterFixed fovy,
#undef M
}
void
cogl_frustum (ClutterFixed left,
ClutterFixed right,
ClutterFixed bottom,
ClutterFixed top,
ClutterFixed z_near,
ClutterFixed z_far)
{
ClutterFixed c, d;
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
GE( cogl_wrap_glMatrixMode (GL_PROJECTION) );
GE( cogl_wrap_glLoadIdentity () );
GE( cogl_wrap_glFrustumx (left, right,
bottom, top,
z_near, z_far) );
GE( cogl_wrap_glMatrixMode (GL_MODELVIEW) );
/* Calculate and store the inverse of the matrix */
memset (ctx->inverse_projection, 0, sizeof (ClutterFixed) * 16);
c = -CFX_QDIV (z_far + z_near, z_far - z_near);
d = -CFX_QDIV (2 * CFX_QMUL (z_far, z_near), z_far - z_near);
#define M(row,col) ctx->inverse_projection[col*4+row]
M(0,0) = CFX_QDIV (right - left, 2 * z_near);
M(0,3) = CFX_QDIV (right + left, 2 * z_near);
M(1,1) = CFX_QDIV (top - bottom, 2 * z_near);
M(1,3) = CFX_QDIV (top + bottom, 2 * z_near);
M(2,3) = -CFX_ONE;
M(3,2) = CFX_QDIV (CFX_ONE, d);
M(3,3) = CFX_QDIV (c, d);
#undef M
}
void
cogl_viewport (guint width,
guint height)
{
GE( glViewport (0, 0, width, height) );
}
void
cogl_setup_viewport (guint w,
guint h,
@ -715,8 +765,6 @@ cogl_setup_viewport (guint w,
ClutterFixed z_camera;
GE( glViewport (0, 0, width, height) );
GE( cogl_wrap_glMatrixMode (GL_PROJECTION) );
GE( cogl_wrap_glLoadIdentity () );
/* For Ortho projection.
* cogl_wrap_glOrthox (0, width << 16, 0, height << 16, -1 << 16, 1 << 16);
@ -724,7 +772,6 @@ cogl_setup_viewport (guint w,
cogl_perspective (fovy, aspect, z_near, z_far);
GE( cogl_wrap_glMatrixMode (GL_MODELVIEW) );
GE( cogl_wrap_glLoadIdentity () );
/*

View File

@ -13,7 +13,9 @@ CoglPixelFormat
CoglBufferTarget
<SUBSECTION>
cogl_perspective
cogl_frustum
cogl_setup_viewport
cogl_viewport
cogl_get_modelview_matrix
cogl_get_projection_matrix
cogl_get_viewport
@ -28,6 +30,8 @@ cogl_rotate
<SUBSECTION>
cogl_clip_set
cogl_clip_unset
cogl_clip_stack_save
cogl_clip_stack_restore
<SUBSECTION>
cogl_enable_depth_test
cogl_alpha_func