From ef76d8e5e2243079126fd98c5425b11aa512094c Mon Sep 17 00:00:00 2001 From: Neil Roberts Date: Fri, 1 Aug 2008 12:23:57 +0000 Subject: [PATCH] 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 --- cogl.h.in | 60 +++++++++++++++++++++++- common/cogl-clip-stack.c | 70 ++++++++++++++++++++++++---- common/cogl-clip-stack.h | 5 -- doc/reference/cogl/cogl-sections.txt | 4 ++ gl/cogl-context.h | 1 + gl/cogl-fbo.c | 48 +++++++++++++++---- gl/cogl-fbo.h | 1 + gl/cogl.c | 67 ++++++++++++++++++++++++-- gles/cogl-gles2-wrapper.c | 25 ++++++++++ gles/cogl-gles2-wrapper.h | 4 ++ gles/cogl.c | 55 ++++++++++++++++++++-- 11 files changed, 307 insertions(+), 33 deletions(-) diff --git a/cogl.h.in b/cogl.h.in index 8653805c2..814ca33c0 100644 --- a/cogl.h.in +++ b/cogl.h.in @@ -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. diff --git a/common/cogl-clip-stack.c b/common/cogl-clip-stack.c index b34dd976a..c24068c4c 100644 --- a/common/cogl-clip-stack.c +++ b/common/cogl-clip-stack.c @@ -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); +} diff --git a/common/cogl-clip-stack.h b/common/cogl-clip-stack.h index 3f3158198..04be889ae 100644 --- a/common/cogl-clip-stack.h +++ b/common/cogl-clip-stack.h @@ -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); diff --git a/doc/reference/cogl/cogl-sections.txt b/doc/reference/cogl/cogl-sections.txt index d95398a65..ed873ce32 100644 --- a/doc/reference/cogl/cogl-sections.txt +++ b/doc/reference/cogl/cogl-sections.txt @@ -13,7 +13,9 @@ CoglPixelFormat CoglBufferTarget 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 cogl_clip_set cogl_clip_unset +cogl_clip_stack_save +cogl_clip_stack_restore cogl_enable_depth_test cogl_alpha_func diff --git a/gl/cogl-context.h b/gl/cogl-context.h index 694147c23..96b3199df 100644 --- a/gl/cogl-context.h +++ b/gl/cogl-context.h @@ -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; diff --git a/gl/cogl-fbo.c b/gl/cogl-fbo.c index 88fd86db0..d0aa13745 100644 --- a/gl/cogl-fbo.c +++ b/gl/cogl-fbo.c @@ -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); } diff --git a/gl/cogl-fbo.h b/gl/cogl-fbo.h index f2dd5298f..f0efef79f 100644 --- a/gl/cogl-fbo.h +++ b/gl/cogl-fbo.h @@ -32,6 +32,7 @@ typedef struct int width; int height; GLuint gl_handle; + GLuint gl_stencil_handle; } CoglFbo; diff --git a/gl/cogl.c b/gl/cogl.c index f79d231ca..690692765 100644 --- a/gl/cogl.c +++ b/gl/cogl.c @@ -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"); diff --git a/gles/cogl-gles2-wrapper.c b/gles/cogl-gles2-wrapper.c index 394ab8e3d..2bdcaf2af 100644 --- a/gles/cogl-gles2-wrapper.c +++ b/gles/cogl-gles2-wrapper.c @@ -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) { diff --git a/gles/cogl-gles2-wrapper.h b/gles/cogl-gles2-wrapper.h index 650bbedd0..9531a486e 100644 --- a/gles/cogl-gles2-wrapper.h +++ b/gles/cogl-gles2-wrapper.h @@ -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 diff --git a/gles/cogl.c b/gles/cogl.c index a4ee269c3..95ca10eef 100644 --- a/gles/cogl.c +++ b/gles/cogl.c @@ -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 () ); /*