diff --git a/cogl/Makefile.am b/cogl/Makefile.am index ac934394a..058551d77 100644 --- a/cogl/Makefile.am +++ b/cogl/Makefile.am @@ -103,6 +103,8 @@ cogl_sources_c = \ $(srcdir)/cogl-bitmap-pixbuf.c \ $(srcdir)/cogl-clip-stack.h \ $(srcdir)/cogl-clip-stack.c \ + $(srcdir)/cogl-clip-state.h \ + $(srcdir)/cogl-clip-state.c \ $(srcdir)/cogl-feature-private.h \ $(srcdir)/cogl-feature-private.c \ $(srcdir)/cogl-fixed.c \ diff --git a/cogl/cogl-clip-stack.c b/cogl/cogl-clip-stack.c index 37c9d022f..83e95afe4 100644 --- a/cogl/cogl-clip-stack.c +++ b/cogl/cogl-clip-stack.c @@ -3,7 +3,7 @@ * * An object oriented GL/GLES Abstraction/Utility Layer * - * Copyright (C) 2007,2008,2009 Intel Corporation. + * Copyright (C) 2007,2008,2009,2010 Intel Corporation. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -40,8 +40,6 @@ #include "cogl-util.h" #include "cogl-path-private.h" -typedef struct _CoglClipStack CoglClipStack; - typedef struct _CoglClipStackEntry CoglClipStackEntry; typedef struct _CoglClipStackEntryRect CoglClipStackEntryRect; typedef struct _CoglClipStackEntryWindowRect CoglClipStackEntryWindowRect; @@ -402,27 +400,16 @@ _cogl_clip_stack_push_entry (CoglClipStack *clip_stack, } void -cogl_clip_push_window_rectangle (int x_offset, - int y_offset, - int width, - int height) +_cogl_clip_stack_push_window_rectangle (CoglClipStack *stack, + int x_offset, + int y_offset, + int width, + int height) { - CoglHandle framebuffer; - CoglClipStackState *clip_state; - CoglClipStack *stack; CoglClipStackEntryWindowRect *entry; _COGL_GET_CONTEXT (ctx, NO_RETVAL); - /* We don't log clip stack changes in the journal so we must flush - * it before making modifications */ - _cogl_journal_flush (); - - framebuffer = _cogl_get_framebuffer (); - clip_state = _cogl_framebuffer_get_clip_state (framebuffer); - - stack = clip_state->stacks->data; - entry = _cogl_clip_stack_push_entry (stack, sizeof (CoglClipStackEntryWindowRect), COGL_CLIP_STACK_WINDOW_RECT); @@ -431,137 +418,18 @@ cogl_clip_push_window_rectangle (int x_offset, entry->x1 = x_offset + width; entry->y0 = y_offset; entry->y1 = y_offset + height; - - clip_state->stack_dirty = TRUE; } -/* XXX: This is deprecated API */ void -cogl_clip_push_window_rect (float x_offset, - float y_offset, - float width, - float height) -{ - cogl_clip_push_window_rectangle (x_offset, y_offset, width, height); -} - -/* Scale from OpenGL normalized device coordinates (ranging from -1 to 1) - * to Cogl window/framebuffer coordinates (ranging from 0 to buffer-size) with - * (0,0) being top left. */ -#define VIEWPORT_TRANSFORM_X(x, vp_origin_x, vp_width) \ - ( ( ((x) + 1.0) * ((vp_width) / 2.0) ) + (vp_origin_x) ) -/* Note: for Y we first flip all coordinates around the X axis while in - * normalized device coodinates */ -#define VIEWPORT_TRANSFORM_Y(y, vp_origin_y, vp_height) \ - ( ( ((-(y)) + 1.0) * ((vp_height) / 2.0) ) + (vp_origin_y) ) - -/* Transform a homogeneous vertex position from model space to Cogl - * window coordinates (with 0,0 being top left) */ -static void -transform_point (CoglMatrix *matrix_mv, - CoglMatrix *matrix_p, - float *viewport, - float *x, - float *y) -{ - float z = 0; - float w = 1; - - /* Apply the modelview matrix transform */ - cogl_matrix_transform_point (matrix_mv, x, y, &z, &w); - - /* Apply the projection matrix transform */ - cogl_matrix_transform_point (matrix_p, x, y, &z, &w); - - /* Perform perspective division */ - *x /= w; - *y /= w; - - /* Apply viewport transform */ - *x = VIEWPORT_TRANSFORM_X (*x, viewport[0], viewport[2]); - *y = VIEWPORT_TRANSFORM_Y (*y, viewport[1], viewport[3]); -} - -#undef VIEWPORT_SCALE_X -#undef VIEWPORT_SCALE_Y - -/* Try to push a rectangle given in object coordinates as a rectangle in window - * coordinates instead of object coordinates */ -gboolean -try_pushing_rect_as_window_rect (float x_1, - float y_1, +_cogl_clip_stack_push_rectangle (CoglClipStack *stack, + float x_1, + float y_1, float x_2, - float y_2) + float y_2, + const CoglMatrix *modelview_matrix) { - CoglMatrix matrix; - CoglMatrix matrix_p; - float v[4]; - - cogl_get_modelview_matrix (&matrix); - - /* If the modelview meets these constraints then a transformed rectangle - * should still be a rectangle when it reaches screen coordinates. - * - * FIXME: we are are making certain assumptions about the projection - * matrix a.t.m and should really be looking at the combined modelview - * and projection matrix. - * FIXME: we don't consider rotations that are a multiple of 90 degrees - * which could be quite common. - */ - if (matrix.xy != 0 || matrix.xz != 0 || - matrix.yx != 0 || matrix.yz != 0 || - matrix.zx != 0 || matrix.zy != 0) - return FALSE; - - cogl_get_projection_matrix (&matrix_p); - cogl_get_viewport (v); - - transform_point (&matrix, &matrix_p, v, &x_1, &y_1); - transform_point (&matrix, &matrix_p, v, &x_2, &y_2); - - /* Consider that the modelview matrix may flip the rectangle - * along the x or y axis... */ -#define SWAP(A,B) do { float tmp = B; B = A; A = tmp; } while (0) - if (x_1 > x_2) - SWAP (x_1, x_2); - if (y_1 > y_2) - SWAP (y_1, y_2); -#undef SWAP - - cogl_clip_push_window_rectangle (COGL_UTIL_NEARBYINT (x_1), - COGL_UTIL_NEARBYINT (y_1), - COGL_UTIL_NEARBYINT (x_2 - x_1), - COGL_UTIL_NEARBYINT (y_2 - y_1)); - return TRUE; -} - -void -cogl_clip_push_rectangle (float x_1, - float y_1, - float x_2, - float y_2) -{ - CoglHandle framebuffer; - CoglClipStackState *clip_state; - CoglClipStack *stack; CoglClipStackEntryRect *entry; - _COGL_GET_CONTEXT (ctx, NO_RETVAL); - - /* We don't log clip stack changes in the journal so we must flush - * it before making modifications */ - _cogl_journal_flush (); - - /* Try and catch window space rectangles so we can redirect to - * cogl_clip_push_window_rect which will use scissoring. */ - if (try_pushing_rect_as_window_rect (x_1, y_1, x_2, y_2)) - return; - - framebuffer = _cogl_get_framebuffer (); - clip_state = _cogl_framebuffer_get_clip_state (framebuffer); - - stack = clip_state->stacks->data; - /* Make a new entry */ entry = _cogl_clip_stack_push_entry (stack, sizeof (CoglClipStackEntryRect), @@ -572,60 +440,23 @@ cogl_clip_push_rectangle (float x_1, entry->x1 = x_2; entry->y1 = y_2; - cogl_get_modelview_matrix (&entry->matrix); - - clip_state->stack_dirty = TRUE; -} - -/* XXX: Deprecated API */ -void -cogl_clip_push (float x_offset, - float y_offset, - float width, - float height) -{ - cogl_clip_push_rectangle (x_offset, - y_offset, - x_offset + width, - y_offset + height); + entry->matrix = *modelview_matrix; } void -cogl_clip_push_from_path_preserve (void) +_cogl_clip_stack_push_from_path (CoglClipStack *stack, + CoglHandle path, + const CoglMatrix *modelview_matrix) { - CoglHandle framebuffer; - CoglClipStackState *clip_state; - CoglClipStack *stack; CoglClipStackEntryPath *entry; - _COGL_GET_CONTEXT (ctx, NO_RETVAL); - - /* We don't log clip stack changes in the journal so we must flush - * it before making modifications */ - _cogl_journal_flush (); - - framebuffer = _cogl_get_framebuffer (); - clip_state = _cogl_framebuffer_get_clip_state (framebuffer); - - stack = clip_state->stacks->data; - entry = _cogl_clip_stack_push_entry (stack, sizeof (CoglClipStackEntryPath), COGL_CLIP_STACK_PATH); - entry->path = cogl_path_copy (cogl_path_get ()); + entry->path = cogl_path_copy (path); - cogl_get_modelview_matrix (&entry->matrix); - - clip_state->stack_dirty = TRUE; -} - -void -cogl_clip_push_from_path (void) -{ - cogl_clip_push_from_path_preserve (); - - cogl_path_new (); + entry->matrix = *modelview_matrix; } static void @@ -660,18 +491,11 @@ _cogl_clip_stack_entry_unref (CoglClipStackEntry *entry) } } -static void -_cogl_clip_pop_real (CoglClipStackState *clip_state) +void +_cogl_clip_stack_pop (CoglClipStack *stack) { - CoglClipStack *stack; CoglClipStackEntry *entry; - /* We don't log clip stack changes in the journal so we must flush - * it before making modifications */ - _cogl_journal_flush (); - - stack = clip_state->stacks->data; - g_return_if_fail (stack->stack_top != NULL); /* To pop we are moving the top of the stack to the old top's parent @@ -687,28 +511,12 @@ _cogl_clip_pop_real (CoglClipStackState *clip_state) if (stack->stack_top) stack->stack_top->ref_count++; _cogl_clip_stack_entry_unref (entry); - - clip_state->stack_dirty = TRUE; } void -cogl_clip_pop (void) +_cogl_clip_stack_flush (CoglClipStack *stack, + gboolean *stencil_used_p) { - CoglHandle framebuffer; - CoglClipStackState *clip_state; - - _COGL_GET_CONTEXT (ctx, NO_RETVAL); - - framebuffer = _cogl_get_framebuffer (); - clip_state = _cogl_framebuffer_get_clip_state (framebuffer); - - _cogl_clip_pop_real (clip_state); -} - -void -_cogl_flush_clip_state (CoglClipStackState *clip_state) -{ - CoglClipStack *stack; int has_clip_planes; gboolean using_clip_planes = FALSE; gboolean using_stencil_buffer = FALSE; @@ -720,26 +528,8 @@ _cogl_flush_clip_state (CoglClipStackState *clip_state) _cogl_framebuffer_get_modelview_stack (_cogl_get_framebuffer ()); CoglClipStackEntry *entry; - if (!clip_state->stack_dirty) - return; - - /* The current primitive journal does not support tracking changes to the - * clip stack... */ - _cogl_journal_flush (); - - /* XXX: the handling of clipping is quite complex. It may involve use of - * the Cogl Journal or other Cogl APIs which may end up recursively - * wanting to ensure the clip state is flushed. We need to ensure we - * don't recurse infinitely... - */ - clip_state->stack_dirty = FALSE; - has_clip_planes = cogl_features_available (COGL_FEATURE_FOUR_CLIP_PLANES); - stack = clip_state->stacks->data; - - clip_state->stencil_used = FALSE; - disable_clip_planes (); disable_stencil_buffer (); GE (glDisable (GL_SCISSOR_TEST)); @@ -854,112 +644,27 @@ _cogl_flush_clip_state (CoglClipStackState *clip_state) scissor_y1 - scissor_y0)); } - clip_state->stencil_used = using_stencil_buffer; + *stencil_used_p = using_stencil_buffer; } -/* XXX: This should never have been made public API! */ -void -cogl_clip_ensure (void) -{ - CoglClipStackState *clip_state; - - clip_state = _cogl_framebuffer_get_clip_state (_cogl_get_framebuffer ()); - _cogl_flush_clip_state (clip_state); -} - -static void -_cogl_clip_stack_save_real (CoglClipStackState *clip_state) +CoglClipStack * +_cogl_clip_stack_new (void) { CoglClipStack *stack; - /* We don't log clip stack changes in the journal so we must flush - * it before making modifications */ - _cogl_journal_flush (); - stack = g_slice_new (CoglClipStack); stack->stack_top = NULL; - clip_state->stacks = g_slist_prepend (clip_state->stacks, stack); - clip_state->stack_dirty = TRUE; + return stack; } void -cogl_clip_stack_save (void) +_cogl_clip_stack_free (CoglClipStack *stack) { - CoglHandle framebuffer; - CoglClipStackState *clip_state; - - _COGL_GET_CONTEXT (ctx, NO_RETVAL); - - framebuffer = _cogl_get_framebuffer (); - clip_state = _cogl_framebuffer_get_clip_state (framebuffer); - - _cogl_clip_stack_save_real (clip_state); -} - -static void -_cogl_clip_stack_restore_real (CoglClipStackState *clip_state) -{ - CoglClipStack *stack; - - g_return_if_fail (clip_state->stacks != NULL); - - /* We don't log clip stack changes in the journal so we must flush - * it before making modifications */ - _cogl_journal_flush (); - - stack = clip_state->stacks->data; - - /* Free the stack. We only need to unref the top node and this + /* We only need to unref the top node and this should end up freeing all of the parents if need be */ if (stack->stack_top) _cogl_clip_stack_entry_unref (stack->stack_top); - /* Revert to an old stack */ g_slice_free (CoglClipStack, stack); - clip_state->stacks = g_slist_delete_link (clip_state->stacks, - clip_state->stacks); - - clip_state->stack_dirty = TRUE; } - -void -cogl_clip_stack_restore (void) -{ - CoglHandle framebuffer; - CoglClipStackState *clip_state; - - _COGL_GET_CONTEXT (ctx, NO_RETVAL); - - framebuffer = _cogl_get_framebuffer (); - clip_state = _cogl_framebuffer_get_clip_state (framebuffer); - - _cogl_clip_stack_restore_real (clip_state); -} - -void -_cogl_clip_stack_state_init (CoglClipStackState *clip_state) -{ - _COGL_GET_CONTEXT (ctx, NO_RETVAL); - - clip_state->stacks = NULL; - clip_state->stack_dirty = TRUE; - - /* Add an intial stack */ - _cogl_clip_stack_save_real (clip_state); -} - -void -_cogl_clip_stack_state_destroy (CoglClipStackState *clip_state) -{ - /* Destroy all of the stacks */ - while (clip_state->stacks) - _cogl_clip_stack_restore_real (clip_state); -} - -void -_cogl_clip_stack_state_dirty (CoglClipStackState *clip_state) -{ - clip_state->stack_dirty = TRUE; -} - diff --git a/cogl/cogl-clip-stack.h b/cogl/cogl-clip-stack.h index 43a4105c9..508cea9db 100644 --- a/cogl/cogl-clip-stack.h +++ b/cogl/cogl-clip-stack.h @@ -3,7 +3,7 @@ * * An object oriented GL/GLES Abstraction/Utility Layer * - * Copyright (C) 2007,2008,2009 Intel Corporation. + * Copyright (C) 2007,2008,2009,2010 Intel Corporation. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -24,27 +24,38 @@ #ifndef __COGL_CLIP_STACK_H #define __COGL_CLIP_STACK_H -typedef struct _CoglClipStackState CoglClipStackState; +typedef struct _CoglClipStack CoglClipStack; -struct _CoglClipStackState -{ - /* Stack of stacks */ - GSList *stacks; - - gboolean stack_dirty; - gboolean stencil_used; -}; +CoglClipStack * +_cogl_clip_stack_new (void); void -_cogl_clip_stack_state_init (CoglClipStackState *state); +_cogl_clip_stack_free (CoglClipStack *stack); void -_cogl_clip_stack_state_destroy (CoglClipStackState *state); +_cogl_clip_stack_push_window_rectangle (CoglClipStack *stack, + int x_offset, + int y_offset, + int width, + int height); void -_cogl_clip_stack_state_dirty (CoglClipStackState *state); +_cogl_clip_stack_push_rectangle (CoglClipStack *stack, + float x_1, + float y_1, + float x_2, + float y_2, + const CoglMatrix *modelview_matrix); void -_cogl_flush_clip_state (CoglClipStackState *clip_state); +_cogl_clip_stack_push_from_path (CoglClipStack *stack, + CoglHandle path, + const CoglMatrix *modelview_matrix); +void +_cogl_clip_stack_pop (CoglClipStack *stack); + +void +_cogl_clip_stack_flush (CoglClipStack *stack, + gboolean *stencil_used_p); #endif /* __COGL_CLIP_STACK_H */ diff --git a/cogl/cogl-clip-state.c b/cogl/cogl-clip-state.c new file mode 100644 index 000000000..c5b7442a6 --- /dev/null +++ b/cogl/cogl-clip-state.c @@ -0,0 +1,405 @@ +/* + * Cogl + * + * An object oriented GL/GLES Abstraction/Utility Layer + * + * Copyright (C) 2007,2008,2009,2010 Intel Corporation. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + * + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include + +#include + +#include "cogl.h" +#include "cogl-clip-stack.h" +#include "cogl-clip-state.h" +#include "cogl-context.h" +#include "cogl-internal.h" +#include "cogl-framebuffer-private.h" +#include "cogl-journal-private.h" +#include "cogl-util.h" + +void +cogl_clip_push_window_rectangle (int x_offset, + int y_offset, + int width, + int height) +{ + CoglHandle framebuffer; + CoglClipState *clip_state; + CoglClipStack *stack; + + _COGL_GET_CONTEXT (ctx, NO_RETVAL); + + /* We don't log clip stack changes in the journal so we must flush + * it before making modifications */ + _cogl_journal_flush (); + + framebuffer = _cogl_get_framebuffer (); + clip_state = _cogl_framebuffer_get_clip_state (framebuffer); + + stack = clip_state->stacks->data; + + _cogl_clip_stack_push_window_rectangle (stack, x_offset, y_offset, + width, height); + + clip_state->stack_dirty = TRUE; +} + +/* XXX: This is deprecated API */ +void +cogl_clip_push_window_rect (float x_offset, + float y_offset, + float width, + float height) +{ + cogl_clip_push_window_rectangle (x_offset, y_offset, width, height); +} + +/* Scale from OpenGL normalized device coordinates (ranging from -1 to 1) + * to Cogl window/framebuffer coordinates (ranging from 0 to buffer-size) with + * (0,0) being top left. */ +#define VIEWPORT_TRANSFORM_X(x, vp_origin_x, vp_width) \ + ( ( ((x) + 1.0) * ((vp_width) / 2.0) ) + (vp_origin_x) ) +/* Note: for Y we first flip all coordinates around the X axis while in + * normalized device coodinates */ +#define VIEWPORT_TRANSFORM_Y(y, vp_origin_y, vp_height) \ + ( ( ((-(y)) + 1.0) * ((vp_height) / 2.0) ) + (vp_origin_y) ) + +/* Transform a homogeneous vertex position from model space to Cogl + * window coordinates (with 0,0 being top left) */ +static void +transform_point (CoglMatrix *matrix_mv, + CoglMatrix *matrix_p, + float *viewport, + float *x, + float *y) +{ + float z = 0; + float w = 1; + + /* Apply the modelview matrix transform */ + cogl_matrix_transform_point (matrix_mv, x, y, &z, &w); + + /* Apply the projection matrix transform */ + cogl_matrix_transform_point (matrix_p, x, y, &z, &w); + + /* Perform perspective division */ + *x /= w; + *y /= w; + + /* Apply viewport transform */ + *x = VIEWPORT_TRANSFORM_X (*x, viewport[0], viewport[2]); + *y = VIEWPORT_TRANSFORM_Y (*y, viewport[1], viewport[3]); +} + +#undef VIEWPORT_SCALE_X +#undef VIEWPORT_SCALE_Y + +/* Try to push a rectangle given in object coordinates as a rectangle in window + * coordinates instead of object coordinates */ +gboolean +try_pushing_rect_as_window_rect (float x_1, + float y_1, + float x_2, + float y_2) +{ + CoglMatrix matrix; + CoglMatrix matrix_p; + float v[4]; + + cogl_get_modelview_matrix (&matrix); + + /* If the modelview meets these constraints then a transformed rectangle + * should still be a rectangle when it reaches screen coordinates. + * + * FIXME: we are are making certain assumptions about the projection + * matrix a.t.m and should really be looking at the combined modelview + * and projection matrix. + * FIXME: we don't consider rotations that are a multiple of 90 degrees + * which could be quite common. + */ + if (matrix.xy != 0 || matrix.xz != 0 || + matrix.yx != 0 || matrix.yz != 0 || + matrix.zx != 0 || matrix.zy != 0) + return FALSE; + + cogl_get_projection_matrix (&matrix_p); + cogl_get_viewport (v); + + transform_point (&matrix, &matrix_p, v, &x_1, &y_1); + transform_point (&matrix, &matrix_p, v, &x_2, &y_2); + + /* Consider that the modelview matrix may flip the rectangle + * along the x or y axis... */ +#define SWAP(A,B) do { float tmp = B; B = A; A = tmp; } while (0) + if (x_1 > x_2) + SWAP (x_1, x_2); + if (y_1 > y_2) + SWAP (y_1, y_2); +#undef SWAP + + cogl_clip_push_window_rectangle (COGL_UTIL_NEARBYINT (x_1), + COGL_UTIL_NEARBYINT (y_1), + COGL_UTIL_NEARBYINT (x_2 - x_1), + COGL_UTIL_NEARBYINT (y_2 - y_1)); + return TRUE; +} + +void +cogl_clip_push_rectangle (float x_1, + float y_1, + float x_2, + float y_2) +{ + CoglHandle framebuffer; + CoglClipState *clip_state; + CoglClipStack *stack; + CoglMatrix modelview_matrix; + + _COGL_GET_CONTEXT (ctx, NO_RETVAL); + + /* We don't log clip stack changes in the journal so we must flush + * it before making modifications */ + _cogl_journal_flush (); + + /* Try and catch window space rectangles so we can redirect to + * cogl_clip_push_window_rect which will use scissoring. */ + if (try_pushing_rect_as_window_rect (x_1, y_1, x_2, y_2)) + return; + + framebuffer = _cogl_get_framebuffer (); + clip_state = _cogl_framebuffer_get_clip_state (framebuffer); + + stack = clip_state->stacks->data; + + cogl_get_modelview_matrix (&modelview_matrix); + + _cogl_clip_stack_push_rectangle (stack, x_1, y_1, x_2, y_2, + &modelview_matrix); + + clip_state->stack_dirty = TRUE; +} + +/* XXX: Deprecated API */ +void +cogl_clip_push (float x_offset, + float y_offset, + float width, + float height) +{ + cogl_clip_push_rectangle (x_offset, + y_offset, + x_offset + width, + y_offset + height); +} + +void +cogl_clip_push_from_path_preserve (void) +{ + CoglHandle framebuffer; + CoglClipState *clip_state; + CoglClipStack *stack; + CoglMatrix modelview_matrix; + + _COGL_GET_CONTEXT (ctx, NO_RETVAL); + + /* We don't log clip stack changes in the journal so we must flush + * it before making modifications */ + _cogl_journal_flush (); + + framebuffer = _cogl_get_framebuffer (); + clip_state = _cogl_framebuffer_get_clip_state (framebuffer); + + stack = clip_state->stacks->data; + + cogl_get_modelview_matrix (&modelview_matrix); + + _cogl_clip_stack_push_from_path (stack, cogl_path_get (), + &modelview_matrix); + + clip_state->stack_dirty = TRUE; +} + +void +cogl_clip_push_from_path (void) +{ + cogl_clip_push_from_path_preserve (); + + cogl_path_new (); +} + +static void +_cogl_clip_pop_real (CoglClipState *clip_state) +{ + CoglClipStack *stack; + + /* We don't log clip stack changes in the journal so we must flush + * it before making modifications */ + _cogl_journal_flush (); + + stack = clip_state->stacks->data; + + _cogl_clip_stack_pop (stack); + + clip_state->stack_dirty = TRUE; +} + +void +cogl_clip_pop (void) +{ + CoglHandle framebuffer; + CoglClipState *clip_state; + + _COGL_GET_CONTEXT (ctx, NO_RETVAL); + + framebuffer = _cogl_get_framebuffer (); + clip_state = _cogl_framebuffer_get_clip_state (framebuffer); + + _cogl_clip_pop_real (clip_state); +} + +void +_cogl_clip_state_flush (CoglClipState *clip_state) +{ + CoglClipStack *stack; + + if (!clip_state->stack_dirty) + return; + + /* The current primitive journal does not support tracking changes to the + * clip stack... */ + _cogl_journal_flush (); + + /* XXX: the handling of clipping is quite complex. It may involve use of + * the Cogl Journal or other Cogl APIs which may end up recursively + * wanting to ensure the clip state is flushed. We need to ensure we + * don't recurse infinitely... + */ + clip_state->stack_dirty = FALSE; + + stack = clip_state->stacks->data; + + _cogl_clip_stack_flush (stack, &clip_state->stencil_used); +} + +/* XXX: This should never have been made public API! */ +void +cogl_clip_ensure (void) +{ + CoglClipState *clip_state; + + clip_state = _cogl_framebuffer_get_clip_state (_cogl_get_framebuffer ()); + _cogl_clip_state_flush (clip_state); +} + +static void +_cogl_clip_stack_save_real (CoglClipState *clip_state) +{ + CoglClipStack *stack; + + /* We don't log clip stack changes in the journal so we must flush + * it before making modifications */ + _cogl_journal_flush (); + + stack = _cogl_clip_stack_new (); + + clip_state->stacks = g_slist_prepend (clip_state->stacks, stack); + clip_state->stack_dirty = TRUE; +} + +void +cogl_clip_stack_save (void) +{ + CoglHandle framebuffer; + CoglClipState *clip_state; + + _COGL_GET_CONTEXT (ctx, NO_RETVAL); + + framebuffer = _cogl_get_framebuffer (); + clip_state = _cogl_framebuffer_get_clip_state (framebuffer); + + _cogl_clip_stack_save_real (clip_state); +} + +static void +_cogl_clip_stack_restore_real (CoglClipState *clip_state) +{ + CoglClipStack *stack; + + g_return_if_fail (clip_state->stacks != NULL); + + /* We don't log clip stack changes in the journal so we must flush + * it before making modifications */ + _cogl_journal_flush (); + + stack = clip_state->stacks->data; + + _cogl_clip_stack_free (stack); + + /* Revert to an old stack */ + clip_state->stacks = g_slist_delete_link (clip_state->stacks, + clip_state->stacks); + + clip_state->stack_dirty = TRUE; +} + +void +cogl_clip_stack_restore (void) +{ + CoglHandle framebuffer; + CoglClipState *clip_state; + + _COGL_GET_CONTEXT (ctx, NO_RETVAL); + + framebuffer = _cogl_get_framebuffer (); + clip_state = _cogl_framebuffer_get_clip_state (framebuffer); + + _cogl_clip_stack_restore_real (clip_state); +} + +void +_cogl_clip_state_init (CoglClipState *clip_state) +{ + _COGL_GET_CONTEXT (ctx, NO_RETVAL); + + clip_state->stacks = NULL; + clip_state->stack_dirty = TRUE; + + /* Add an intial stack */ + _cogl_clip_stack_save_real (clip_state); +} + +void +_cogl_clip_state_destroy (CoglClipState *clip_state) +{ + /* Destroy all of the stacks */ + while (clip_state->stacks) + _cogl_clip_stack_restore_real (clip_state); +} + +void +_cogl_clip_state_dirty (CoglClipState *clip_state) +{ + clip_state->stack_dirty = TRUE; +} diff --git a/cogl/cogl-clip-state.h b/cogl/cogl-clip-state.h new file mode 100644 index 000000000..0f292dd55 --- /dev/null +++ b/cogl/cogl-clip-state.h @@ -0,0 +1,50 @@ +/* + * Cogl + * + * An object oriented GL/GLES Abstraction/Utility Layer + * + * Copyright (C) 2007,2008,2009,2010 Intel Corporation. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + * + * + */ + +#ifndef __COGL_CLIP_STATE_H +#define __COGL_CLIP_STATE_H + +typedef struct _CoglClipState CoglClipState; + +struct _CoglClipState +{ + /* Stack of CoglClipStacks */ + GSList *stacks; + + gboolean stack_dirty; + gboolean stencil_used; +}; + +void +_cogl_clip_state_init (CoglClipState *state); + +void +_cogl_clip_state_destroy (CoglClipState *state); + +void +_cogl_clip_state_dirty (CoglClipState *state); + +void +_cogl_clip_state_flush (CoglClipState *clip_state); + +#endif /* __COGL_CLIP_STATE_H */ diff --git a/cogl/cogl-framebuffer-private.h b/cogl/cogl-framebuffer-private.h index d5d19a5fc..71edfa046 100644 --- a/cogl/cogl-framebuffer-private.h +++ b/cogl/cogl-framebuffer-private.h @@ -26,7 +26,7 @@ #include "cogl-handle.h" #include "cogl-matrix-stack.h" -#include "cogl-clip-stack.h" +#include "cogl-clip-state.h" typedef enum _CoglFramebufferType { COGL_FRAMEBUFFER_TYPE_ONSCREEN, @@ -47,7 +47,7 @@ typedef struct int viewport_width; int viewport_height; - CoglClipStackState clip_state; + CoglClipState clip_state; } CoglFramebuffer; #define COGL_FRAMEBUFFER(X) ((CoglFramebuffer *)(X)) @@ -75,7 +75,7 @@ int _cogl_framebuffer_get_width (CoglHandle handle); int _cogl_framebuffer_get_height (CoglHandle handle); -CoglClipStackState * +CoglClipState * _cogl_framebuffer_get_clip_state (CoglHandle handle); void _cogl_framebuffer_set_viewport (CoglHandle handle, diff --git a/cogl/cogl-framebuffer.c b/cogl/cogl-framebuffer.c index 3b00a8551..082abf5f6 100644 --- a/cogl/cogl-framebuffer.c +++ b/cogl/cogl-framebuffer.c @@ -131,13 +131,13 @@ _cogl_framebuffer_init (CoglFramebuffer *framebuffer, framebuffer->projection_stack = _cogl_matrix_stack_new (); /* Initialise the clip stack */ - _cogl_clip_stack_state_init (&framebuffer->clip_state); + _cogl_clip_state_init (&framebuffer->clip_state); } void _cogl_framebuffer_free (CoglFramebuffer *framebuffer) { - _cogl_clip_stack_state_destroy (&framebuffer->clip_state); + _cogl_clip_state_destroy (&framebuffer->clip_state); _cogl_matrix_stack_destroy (framebuffer->modelview_stack); framebuffer->modelview_stack = NULL; @@ -160,7 +160,7 @@ _cogl_framebuffer_get_height (CoglHandle handle) return framebuffer->height; } -CoglClipStackState * +CoglClipState * _cogl_framebuffer_get_clip_state (CoglHandle handle) { CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (handle); @@ -551,7 +551,7 @@ _cogl_set_framebuffer_real (CoglFramebuffer *framebuffer) * we flush */ _cogl_matrix_stack_dirty (framebuffer->modelview_stack); _cogl_matrix_stack_dirty (framebuffer->projection_stack); - _cogl_clip_stack_state_dirty (&framebuffer->clip_state); + _cogl_clip_state_dirty (&framebuffer->clip_state); } void @@ -697,7 +697,7 @@ _cogl_framebuffer_flush_state (CoglHandle handle, /* XXX: Flushing clip state may trash the modelview and projection * matrices so we must do it before flushing the matrices... */ - _cogl_flush_clip_state (&framebuffer->clip_state); + _cogl_clip_state_flush (&framebuffer->clip_state); if (!(flags & COGL_FRAMEBUFFER_FLUSH_SKIP_MODELVIEW)) _cogl_matrix_stack_flush_to_gl (framebuffer->modelview_stack, diff --git a/cogl/cogl-path.c b/cogl/cogl-path.c index 1a7555859..2e1481db6 100644 --- a/cogl/cogl-path.c +++ b/cogl/cogl-path.c @@ -563,7 +563,7 @@ _cogl_path_fill_nodes (void) cogl_features_available (COGL_FEATURE_STENCIL_BUFFER)) { CoglHandle framebuffer; - CoglClipStackState *clip_state; + CoglClipState *clip_state; _cogl_journal_flush (); @@ -586,7 +586,7 @@ _cogl_path_fill_nodes (void) * we call cogl_flush() to emtpy the journal. */ cogl_flush (); - _cogl_clip_stack_state_dirty (clip_state); + _cogl_clip_state_dirty (clip_state); } else { diff --git a/cogl/cogl.c b/cogl/cogl.c index 60761af0a..ad2e64eb3 100644 --- a/cogl/cogl.c +++ b/cogl/cogl.c @@ -1043,7 +1043,7 @@ cogl_set_projection_matrix (CoglMatrix *matrix) _COGL_MATRIX_DEBUG_PRINT (matrix); } -CoglClipStackState * +CoglClipState * _cogl_get_clip_state (void) { CoglHandle framebuffer;