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
* clutter/clutter-timeline.c: Calculate the 'duration' property
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);
* 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)
{
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 */
}
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)
{
ClutterTexture *texture = CLUTTER_TEXTURE (self);
{
ClutterMainContext *context;
ClutterShader *shader = NULL;
+ ClutterActor *stage = NULL;
+ ClutterPerspective perspective;
context = clutter_context_get_default ();
/* 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);
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));
* 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>
* @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_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
* @height: Height of the viewport
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:
*
* Store the current model-view matrix on the matrix stack. The matrix
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.
*
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;
};
static GList *cogl_clip_stack_top = NULL;
-static GList *cogl_clip_stack_bottom = NULL;
static int cogl_clip_stack_depth = 0;
static void
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;
/* 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
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 */
{
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)
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;
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;
}
}
}
+
+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);
+}
#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);
/* 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;
/* 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
CoglTexSliceSpan *y_span;
GLuint tex_gl_handle;
GLuint fbo_gl_handle;
+ GLuint gl_stencil_handle;
GLenum status;
_COGL_GET_CONTEXT (ctx, COGL_INVALID_HANDLE);
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) );
/* 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);
/* 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);
}
int width;
int height;
GLuint gl_handle;
+ GLuint gl_stencil_handle;
} CoglFbo;
memset (&m[0], 0, sizeof (m));
+ GE( glMatrixMode (GL_PROJECTION) );
+ GE( glLoadIdentity () );
+
/*
* Based on the original algorithm in perspective():
*
GE( glMultMatrixf (m) );
+ GE( glMatrixMode (GL_MODELVIEW) );
+
/* Calculate and store the inverse of the matrix */
memset (ctx->inverse_projection, 0, sizeof (GLfloat) * 16);
}
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,
ClutterFixed fovy,
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 () );
/*
(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");
}
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)
{
float matrix[16];
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);
#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
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
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);
}
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,
ClutterFixed fovy,
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);
cogl_perspective (fovy, aspect, z_near, z_far);
- GE( cogl_wrap_glMatrixMode (GL_MODELVIEW) );
GE( cogl_wrap_glLoadIdentity () );
/*
CoglBufferTarget
<SUBSECTION>
cogl_perspective
+cogl_frustum
cogl_setup_viewport
+cogl_viewport
cogl_get_modelview_matrix
cogl_get_projection_matrix
cogl_get_viewport
<SUBSECTION>
cogl_clip_set
cogl_clip_unset
+cogl_clip_stack_save
+cogl_clip_stack_restore
<SUBSECTION>
cogl_enable_depth_test
cogl_alpha_func