Separate out CoglClipStackState from cogl-clip-stack.c

CoglClipStackState has now been renamed to CoglClipState and is moved
to a separate file. CoglClipStack now just maintains a stack and
doesn't worry about the rest of the state. CoglClipStack sill contains
the code to flush the stack to GL.
This commit is contained in:
Neil Roberts 2010-04-14 19:41:08 +01:00
parent 07a76aacfb
commit f6f375cb36
9 changed files with 520 additions and 347 deletions

View File

@ -103,6 +103,8 @@ cogl_sources_c = \
$(srcdir)/cogl-bitmap-pixbuf.c \ $(srcdir)/cogl-bitmap-pixbuf.c \
$(srcdir)/cogl-clip-stack.h \ $(srcdir)/cogl-clip-stack.h \
$(srcdir)/cogl-clip-stack.c \ $(srcdir)/cogl-clip-stack.c \
$(srcdir)/cogl-clip-state.h \
$(srcdir)/cogl-clip-state.c \
$(srcdir)/cogl-feature-private.h \ $(srcdir)/cogl-feature-private.h \
$(srcdir)/cogl-feature-private.c \ $(srcdir)/cogl-feature-private.c \
$(srcdir)/cogl-fixed.c \ $(srcdir)/cogl-fixed.c \

View File

@ -3,7 +3,7 @@
* *
* An object oriented GL/GLES Abstraction/Utility Layer * 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 * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * modify it under the terms of the GNU Lesser General Public
@ -40,8 +40,6 @@
#include "cogl-util.h" #include "cogl-util.h"
#include "cogl-path-private.h" #include "cogl-path-private.h"
typedef struct _CoglClipStack CoglClipStack;
typedef struct _CoglClipStackEntry CoglClipStackEntry; typedef struct _CoglClipStackEntry CoglClipStackEntry;
typedef struct _CoglClipStackEntryRect CoglClipStackEntryRect; typedef struct _CoglClipStackEntryRect CoglClipStackEntryRect;
typedef struct _CoglClipStackEntryWindowRect CoglClipStackEntryWindowRect; typedef struct _CoglClipStackEntryWindowRect CoglClipStackEntryWindowRect;
@ -402,27 +400,16 @@ _cogl_clip_stack_push_entry (CoglClipStack *clip_stack,
} }
void void
cogl_clip_push_window_rectangle (int x_offset, _cogl_clip_stack_push_window_rectangle (CoglClipStack *stack,
int y_offset, int x_offset,
int width, int y_offset,
int height) int width,
int height)
{ {
CoglHandle framebuffer;
CoglClipStackState *clip_state;
CoglClipStack *stack;
CoglClipStackEntryWindowRect *entry; CoglClipStackEntryWindowRect *entry;
_COGL_GET_CONTEXT (ctx, NO_RETVAL); _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, entry = _cogl_clip_stack_push_entry (stack,
sizeof (CoglClipStackEntryWindowRect), sizeof (CoglClipStackEntryWindowRect),
COGL_CLIP_STACK_WINDOW_RECT); COGL_CLIP_STACK_WINDOW_RECT);
@ -431,137 +418,18 @@ cogl_clip_push_window_rectangle (int x_offset,
entry->x1 = x_offset + width; entry->x1 = x_offset + width;
entry->y0 = y_offset; entry->y0 = y_offset;
entry->y1 = y_offset + height; entry->y1 = y_offset + height;
clip_state->stack_dirty = TRUE;
} }
/* XXX: This is deprecated API */
void void
cogl_clip_push_window_rect (float x_offset, _cogl_clip_stack_push_rectangle (CoglClipStack *stack,
float y_offset, float x_1,
float width, float y_1,
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 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; 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 */ /* Make a new entry */
entry = _cogl_clip_stack_push_entry (stack, entry = _cogl_clip_stack_push_entry (stack,
sizeof (CoglClipStackEntryRect), sizeof (CoglClipStackEntryRect),
@ -572,60 +440,23 @@ cogl_clip_push_rectangle (float x_1,
entry->x1 = x_2; entry->x1 = x_2;
entry->y1 = y_2; entry->y1 = y_2;
cogl_get_modelview_matrix (&entry->matrix); entry->matrix = *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 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; 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, entry = _cogl_clip_stack_push_entry (stack,
sizeof (CoglClipStackEntryPath), sizeof (CoglClipStackEntryPath),
COGL_CLIP_STACK_PATH); COGL_CLIP_STACK_PATH);
entry->path = cogl_path_copy (cogl_path_get ()); entry->path = cogl_path_copy (path);
cogl_get_modelview_matrix (&entry->matrix); entry->matrix = *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 static void
@ -660,18 +491,11 @@ _cogl_clip_stack_entry_unref (CoglClipStackEntry *entry)
} }
} }
static void void
_cogl_clip_pop_real (CoglClipStackState *clip_state) _cogl_clip_stack_pop (CoglClipStack *stack)
{ {
CoglClipStack *stack;
CoglClipStackEntry *entry; 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); g_return_if_fail (stack->stack_top != NULL);
/* To pop we are moving the top of the stack to the old top's parent /* 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) if (stack->stack_top)
stack->stack_top->ref_count++; stack->stack_top->ref_count++;
_cogl_clip_stack_entry_unref (entry); _cogl_clip_stack_entry_unref (entry);
clip_state->stack_dirty = TRUE;
} }
void 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; int has_clip_planes;
gboolean using_clip_planes = FALSE; gboolean using_clip_planes = FALSE;
gboolean using_stencil_buffer = 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 ()); _cogl_framebuffer_get_modelview_stack (_cogl_get_framebuffer ());
CoglClipStackEntry *entry; 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); 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_clip_planes ();
disable_stencil_buffer (); disable_stencil_buffer ();
GE (glDisable (GL_SCISSOR_TEST)); GE (glDisable (GL_SCISSOR_TEST));
@ -854,112 +644,27 @@ _cogl_flush_clip_state (CoglClipStackState *clip_state)
scissor_y1 - scissor_y0)); 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! */ CoglClipStack *
void _cogl_clip_stack_new (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 *stack; 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 = g_slice_new (CoglClipStack);
stack->stack_top = NULL; stack->stack_top = NULL;
clip_state->stacks = g_slist_prepend (clip_state->stacks, stack); return stack;
clip_state->stack_dirty = TRUE;
} }
void void
cogl_clip_stack_save (void) _cogl_clip_stack_free (CoglClipStack *stack)
{ {
CoglHandle framebuffer; /* We only need to unref the top node and this
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
should end up freeing all of the parents if need be */ should end up freeing all of the parents if need be */
if (stack->stack_top) if (stack->stack_top)
_cogl_clip_stack_entry_unref (stack->stack_top); _cogl_clip_stack_entry_unref (stack->stack_top);
/* Revert to an old stack */
g_slice_free (CoglClipStack, 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;
}

View File

@ -3,7 +3,7 @@
* *
* An object oriented GL/GLES Abstraction/Utility Layer * 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 * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * modify it under the terms of the GNU Lesser General Public
@ -24,27 +24,38 @@
#ifndef __COGL_CLIP_STACK_H #ifndef __COGL_CLIP_STACK_H
#define __COGL_CLIP_STACK_H #define __COGL_CLIP_STACK_H
typedef struct _CoglClipStackState CoglClipStackState; typedef struct _CoglClipStack CoglClipStack;
struct _CoglClipStackState CoglClipStack *
{ _cogl_clip_stack_new (void);
/* Stack of stacks */
GSList *stacks;
gboolean stack_dirty;
gboolean stencil_used;
};
void void
_cogl_clip_stack_state_init (CoglClipStackState *state); _cogl_clip_stack_free (CoglClipStack *stack);
void 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 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 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 */ #endif /* __COGL_CLIP_STACK_H */

405
cogl/cogl-clip-state.c Normal file
View File

@ -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 <http://www.gnu.org/licenses/>.
*
*
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <string.h>
#include <math.h>
#include <glib.h>
#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;
}

50
cogl/cogl-clip-state.h Normal file
View File

@ -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 <http://www.gnu.org/licenses/>.
*
*
*/
#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 */

View File

@ -26,7 +26,7 @@
#include "cogl-handle.h" #include "cogl-handle.h"
#include "cogl-matrix-stack.h" #include "cogl-matrix-stack.h"
#include "cogl-clip-stack.h" #include "cogl-clip-state.h"
typedef enum _CoglFramebufferType { typedef enum _CoglFramebufferType {
COGL_FRAMEBUFFER_TYPE_ONSCREEN, COGL_FRAMEBUFFER_TYPE_ONSCREEN,
@ -47,7 +47,7 @@ typedef struct
int viewport_width; int viewport_width;
int viewport_height; int viewport_height;
CoglClipStackState clip_state; CoglClipState clip_state;
} CoglFramebuffer; } CoglFramebuffer;
#define COGL_FRAMEBUFFER(X) ((CoglFramebuffer *)(X)) #define COGL_FRAMEBUFFER(X) ((CoglFramebuffer *)(X))
@ -75,7 +75,7 @@ int
_cogl_framebuffer_get_width (CoglHandle handle); _cogl_framebuffer_get_width (CoglHandle handle);
int int
_cogl_framebuffer_get_height (CoglHandle handle); _cogl_framebuffer_get_height (CoglHandle handle);
CoglClipStackState * CoglClipState *
_cogl_framebuffer_get_clip_state (CoglHandle handle); _cogl_framebuffer_get_clip_state (CoglHandle handle);
void void
_cogl_framebuffer_set_viewport (CoglHandle handle, _cogl_framebuffer_set_viewport (CoglHandle handle,

View File

@ -131,13 +131,13 @@ _cogl_framebuffer_init (CoglFramebuffer *framebuffer,
framebuffer->projection_stack = _cogl_matrix_stack_new (); framebuffer->projection_stack = _cogl_matrix_stack_new ();
/* Initialise the clip stack */ /* Initialise the clip stack */
_cogl_clip_stack_state_init (&framebuffer->clip_state); _cogl_clip_state_init (&framebuffer->clip_state);
} }
void void
_cogl_framebuffer_free (CoglFramebuffer *framebuffer) _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); _cogl_matrix_stack_destroy (framebuffer->modelview_stack);
framebuffer->modelview_stack = NULL; framebuffer->modelview_stack = NULL;
@ -160,7 +160,7 @@ _cogl_framebuffer_get_height (CoglHandle handle)
return framebuffer->height; return framebuffer->height;
} }
CoglClipStackState * CoglClipState *
_cogl_framebuffer_get_clip_state (CoglHandle handle) _cogl_framebuffer_get_clip_state (CoglHandle handle)
{ {
CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (handle); CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (handle);
@ -551,7 +551,7 @@ _cogl_set_framebuffer_real (CoglFramebuffer *framebuffer)
* we flush */ * we flush */
_cogl_matrix_stack_dirty (framebuffer->modelview_stack); _cogl_matrix_stack_dirty (framebuffer->modelview_stack);
_cogl_matrix_stack_dirty (framebuffer->projection_stack); _cogl_matrix_stack_dirty (framebuffer->projection_stack);
_cogl_clip_stack_state_dirty (&framebuffer->clip_state); _cogl_clip_state_dirty (&framebuffer->clip_state);
} }
void void
@ -697,7 +697,7 @@ _cogl_framebuffer_flush_state (CoglHandle handle,
/* XXX: Flushing clip state may trash the modelview and projection /* XXX: Flushing clip state may trash the modelview and projection
* matrices so we must do it before flushing the matrices... * 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)) if (!(flags & COGL_FRAMEBUFFER_FLUSH_SKIP_MODELVIEW))
_cogl_matrix_stack_flush_to_gl (framebuffer->modelview_stack, _cogl_matrix_stack_flush_to_gl (framebuffer->modelview_stack,

View File

@ -563,7 +563,7 @@ _cogl_path_fill_nodes (void)
cogl_features_available (COGL_FEATURE_STENCIL_BUFFER)) cogl_features_available (COGL_FEATURE_STENCIL_BUFFER))
{ {
CoglHandle framebuffer; CoglHandle framebuffer;
CoglClipStackState *clip_state; CoglClipState *clip_state;
_cogl_journal_flush (); _cogl_journal_flush ();
@ -586,7 +586,7 @@ _cogl_path_fill_nodes (void)
* we call cogl_flush() to emtpy the journal. * we call cogl_flush() to emtpy the journal.
*/ */
cogl_flush (); cogl_flush ();
_cogl_clip_stack_state_dirty (clip_state); _cogl_clip_state_dirty (clip_state);
} }
else else
{ {

View File

@ -1043,7 +1043,7 @@ cogl_set_projection_matrix (CoglMatrix *matrix)
_COGL_MATRIX_DEBUG_PRINT (matrix); _COGL_MATRIX_DEBUG_PRINT (matrix);
} }
CoglClipStackState * CoglClipState *
_cogl_get_clip_state (void) _cogl_get_clip_state (void)
{ {
CoglHandle framebuffer; CoglHandle framebuffer;