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:
parent
07a76aacfb
commit
f6f375cb36
9 changed files with 520 additions and 347 deletions
|
@ -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 \
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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 */
|
||||
|
|
405
cogl/cogl-clip-state.c
Normal file
405
cogl/cogl-clip-state.c
Normal 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
50
cogl/cogl-clip-state.h
Normal 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 */
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -1043,7 +1043,7 @@ cogl_set_projection_matrix (CoglMatrix *matrix)
|
|||
_COGL_MATRIX_DEBUG_PRINT (matrix);
|
||||
}
|
||||
|
||||
CoglClipStackState *
|
||||
CoglClipState *
|
||||
_cogl_get_clip_state (void)
|
||||
{
|
||||
CoglHandle framebuffer;
|
||||
|
|
Loading…
Reference in a new issue