mirror of
https://github.com/brl/mutter.git
synced 2024-11-23 00:20:42 -05:00
Merge commit 'git-svn' into multiple-texture-rectangle
Conflicts: clutter/cogl/gl/cogl-texture.c
This commit is contained in:
commit
3b5eb3afeb
88
cogl-path.h
88
cogl-path.h
@ -82,28 +82,60 @@ void cogl_rectanglex (CoglFixed x,
|
||||
/**
|
||||
* cogl_path_fill:
|
||||
*
|
||||
* Fills the constructed shape using the current drawing color.
|
||||
* Fills the constructed shape using the current drawing color. The
|
||||
* current path is then cleared. To use the path again, call
|
||||
* cogl_path_fill_preserve() instead.
|
||||
**/
|
||||
void cogl_path_fill (void);
|
||||
void cogl_path_fill (void);
|
||||
|
||||
/**
|
||||
* cogl_path_fill_preserve:
|
||||
*
|
||||
* Fills the constructed shape using the current drawing color and
|
||||
* preserves the path to be used again.
|
||||
*
|
||||
* Since: 1.0
|
||||
**/
|
||||
void cogl_path_fill_preserve (void);
|
||||
|
||||
/**
|
||||
* cogl_path_stroke:
|
||||
*
|
||||
* Strokes the constructed shape using the current drawing color
|
||||
* and a width of 1 pixel (regardless of the current transformation
|
||||
* matrix).
|
||||
* Strokes the constructed shape using the current drawing color and a
|
||||
* width of 1 pixel (regardless of the current transformation
|
||||
* matrix). To current path is then cleared. To use the path again,
|
||||
* call cogl_path_stroke_preserve() instead.
|
||||
**/
|
||||
void cogl_path_stroke (void);
|
||||
void cogl_path_stroke (void);
|
||||
|
||||
|
||||
/**
|
||||
* cogl_path_stroke_preserve:
|
||||
*
|
||||
* Strokes the constructed shape using the current drawing color and
|
||||
* preserves the path to be used again.
|
||||
*
|
||||
* Since: 1.0
|
||||
**/
|
||||
void cogl_path_stroke_preserve (void);
|
||||
|
||||
/**
|
||||
* cogl_path_new:
|
||||
*
|
||||
* Clears the current path and starts a new one.
|
||||
*
|
||||
* Since: 1.0
|
||||
*/
|
||||
void cogl_path_new (void);
|
||||
|
||||
/**
|
||||
* cogl_path_move_to:
|
||||
* @x: X coordinate of the pen location to move to.
|
||||
* @y: Y coordinate of the pen location to move to.
|
||||
*
|
||||
* Clears the previously constructed shape and begins a new path
|
||||
* contour by moving the pen to the given coordinates.
|
||||
**/
|
||||
* Moves the pen to the given location. If there is an existing path
|
||||
* this will start a new disjoint subpath.
|
||||
**/
|
||||
void cogl_path_move_to (CoglFixed x,
|
||||
CoglFixed y);
|
||||
|
||||
@ -113,9 +145,9 @@ void cogl_path_move_to (CoglFixed x,
|
||||
* @x: X offset from the current pen location to move the pen to.
|
||||
* @y: Y offset from the current pen location to move the pen to.
|
||||
*
|
||||
* Clears the previously constructed shape and begins a new path
|
||||
* contour by moving the pen to the given coordinates relative
|
||||
* to the current pen location.
|
||||
* Moves the pen to the given offset relative to the current pen
|
||||
* location. If there is an existing path this will start a new
|
||||
* disjoint subpath.
|
||||
**/
|
||||
void cogl_path_rel_move_to (CoglFixed x,
|
||||
CoglFixed y);
|
||||
@ -222,8 +254,9 @@ void cogl_path_close (void);
|
||||
* @x2: X coordinate of the end line vertex
|
||||
* @y2: Y coordinate of the end line vertex
|
||||
*
|
||||
* Clears the previously constructed shape and constructs a straight
|
||||
* line shape start and ending at the given coordinates.
|
||||
* Constructs a straight line shape starting and ending at the given
|
||||
* coordinates. If there is an existing path this will start a new
|
||||
* disjoint sub-path.
|
||||
**/
|
||||
void cogl_path_line (CoglFixed x1,
|
||||
CoglFixed y1,
|
||||
@ -236,10 +269,11 @@ void cogl_path_line (CoglFixed x1,
|
||||
* values that specify the vertex coordinates.
|
||||
* @num_points: The total number of vertices.
|
||||
*
|
||||
* Clears the previously constructed shape and constructs a series of straight
|
||||
* line segments, starting from the first given vertex coordinate. Each
|
||||
* subsequent segment stars where the previous one ended and ends at the next
|
||||
* given vertex coordinate.
|
||||
* Constructs a series of straight line segments, starting from the
|
||||
* first given vertex coordinate. If there is an existing path this
|
||||
* will start a new disjoint sub-path. Each subsequent segment starts
|
||||
* where the previous one ended and ends at the next given vertex
|
||||
* coordinate.
|
||||
*
|
||||
* The coords array must contain 2 * num_points values. The first value
|
||||
* represents the X coordinate of the first vertex, the second value
|
||||
@ -257,8 +291,8 @@ void cogl_path_polyline (CoglFixed *coords,
|
||||
* values that specify the vertex coordinates.
|
||||
* @num_points: The total number of vertices.
|
||||
*
|
||||
* Clears the previously constructed shape and constructs a polygonal
|
||||
* shape of the given number of vertices.
|
||||
* Constructs a polygonal shape of the given number of vertices. If
|
||||
* there is an existing path this will start a new disjoint sub-path.
|
||||
*
|
||||
* The coords array must contain 2 * num_points values. The first value
|
||||
* represents the X coordinate of the first vertex, the second value
|
||||
@ -276,8 +310,8 @@ void cogl_path_polygon (CoglFixed *coords,
|
||||
* @width: Rectangle width.
|
||||
* @height: Rectangle height.
|
||||
*
|
||||
* Clears the previously constructed shape and constructs a rectangular
|
||||
* shape at the given coordinates.
|
||||
* Constructs a rectangular shape at the given coordinates. If there
|
||||
* is an existing path this will start a new disjoint sub-path.
|
||||
**/
|
||||
void cogl_path_rectangle (CoglFixed x,
|
||||
CoglFixed y,
|
||||
@ -291,8 +325,8 @@ void cogl_path_rectangle (CoglFixed x,
|
||||
* @radius_x: X radius of the ellipse
|
||||
* @radius_y: Y radius of the ellipse
|
||||
*
|
||||
* Clears the previously constructed shape and constructs an ellipse
|
||||
* shape.
|
||||
* Constructs an ellipse shape. If there is an existing path this will
|
||||
* start a new disjoint sub-path.
|
||||
**/
|
||||
void cogl_path_ellipse (CoglFixed center_x,
|
||||
CoglFixed center_y,
|
||||
@ -309,9 +343,9 @@ void cogl_path_ellipse (CoglFixed center_x,
|
||||
* @arc_step: Angle increment resolution for subdivision of
|
||||
* the corner arcs.
|
||||
*
|
||||
* Clears the previously constructed shape and constructs a rectangular
|
||||
* shape with rounded corners.
|
||||
**/
|
||||
* Constructs a rectangular shape with rounded corners. If there is an
|
||||
* existing path this will start a new disjoint sub-path.
|
||||
**/
|
||||
void cogl_path_round_rectangle (CoglFixed x,
|
||||
CoglFixed y,
|
||||
CoglFixed width,
|
||||
|
43
cogl.h.in
43
cogl.h.in
@ -332,20 +332,59 @@ void cogl_get_viewport (CoglFixed v[4]);
|
||||
* will be clipped so that only the portion inside the rectangle will
|
||||
* be displayed. The rectangle dimensions are transformed by the
|
||||
* current model-view matrix.
|
||||
*
|
||||
* The rectangle is intersected with the current clip region. To undo
|
||||
* the effect of this function, call cogl_clip_unset().
|
||||
*/
|
||||
void cogl_clip_set (CoglFixed x_offset,
|
||||
CoglFixed y_offset,
|
||||
CoglFixed width,
|
||||
CoglFixed height);
|
||||
|
||||
/**
|
||||
* cogl_clip_set_from_path:
|
||||
*
|
||||
* Sets a new clipping area using the current path. The current path
|
||||
* is then cleared. The clipping area is intersected with the previous
|
||||
* clipping area. To restore the previous clipping area, call
|
||||
* cogl_clip_unset().
|
||||
*
|
||||
* Since: 1.0
|
||||
*/
|
||||
void cogl_clip_set_from_path (void);
|
||||
|
||||
/**
|
||||
* cogl_clip_set_from_path_preserve:
|
||||
*
|
||||
* Sets a new clipping area using the current path. The current path
|
||||
* is then cleared. The clipping area is intersected with the previous
|
||||
* clipping area. To restore the previous clipping area, call
|
||||
* cogl_clip_unset().
|
||||
*
|
||||
* Since: 1.0
|
||||
*/
|
||||
void cogl_clip_set_from_path_preserve (void);
|
||||
|
||||
/**
|
||||
* cogl_clip_unset:
|
||||
*
|
||||
* Removes the current clipping rectangle so that all drawing
|
||||
* operations extend to full size of the viewport again.
|
||||
* Reverts the clipping region to the state before the last call to
|
||||
* cogl_clip_set().
|
||||
*/
|
||||
void cogl_clip_unset (void);
|
||||
|
||||
/**
|
||||
* cogl_clip_ensure:
|
||||
*
|
||||
* Ensures that the current clipping region has been set in GL. This
|
||||
* will automatically be called before any Cogl primitives but it
|
||||
* maybe be neccessary to call if you are using raw GL calls with
|
||||
* clipping.
|
||||
*
|
||||
* Since: 1.0
|
||||
*/
|
||||
void cogl_clip_ensure (void);
|
||||
|
||||
/**
|
||||
* cogl_clip_stack_save:
|
||||
*
|
||||
|
@ -27,8 +27,11 @@
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <string.h>
|
||||
#include "cogl.h"
|
||||
#include "cogl-clip-stack.h"
|
||||
#include "cogl-primitives.h"
|
||||
#include "cogl-context.h"
|
||||
|
||||
/* These are defined in the particular backend (float in GL vs fixed
|
||||
in GL ES) */
|
||||
@ -36,58 +39,64 @@ void _cogl_set_clip_planes (CoglFixed x,
|
||||
CoglFixed y,
|
||||
CoglFixed width,
|
||||
CoglFixed height);
|
||||
void _cogl_init_stencil_buffer (void);
|
||||
void _cogl_add_stencil_clip (CoglFixed x,
|
||||
CoglFixed y,
|
||||
CoglFixed width,
|
||||
CoglFixed height,
|
||||
gboolean first);
|
||||
void _cogl_add_path_to_stencil_buffer (CoglFixedVec2 nodes_min,
|
||||
CoglFixedVec2 nodes_max,
|
||||
guint path_size,
|
||||
CoglPathNode *path,
|
||||
gboolean merge);
|
||||
void _cogl_enable_clip_planes (void);
|
||||
void _cogl_disable_clip_planes (void);
|
||||
void _cogl_disable_stencil_buffer (void);
|
||||
void _cogl_set_matrix (const CoglFixed *matrix);
|
||||
|
||||
typedef struct _CoglClipStackEntry CoglClipStackEntry;
|
||||
typedef struct _CoglClipStack CoglClipStack;
|
||||
|
||||
struct _CoglClipStackEntry
|
||||
typedef struct _CoglClipStackEntryRect CoglClipStackEntryRect;
|
||||
typedef struct _CoglClipStackEntryPath CoglClipStackEntryPath;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
COGL_CLIP_STACK_RECT,
|
||||
COGL_CLIP_STACK_PATH
|
||||
} CoglClipStackEntryType;
|
||||
|
||||
struct _CoglClipStack
|
||||
{
|
||||
/* If this is set then this entry clears the clip stack. This is
|
||||
used to clear the stack when drawing an FBO put to keep the
|
||||
entries so they can be restored when the FBO drawing is
|
||||
completed */
|
||||
gboolean clear;
|
||||
|
||||
/* The rectangle for this clip */
|
||||
CoglFixed x_offset;
|
||||
CoglFixed y_offset;
|
||||
CoglFixed width;
|
||||
CoglFixed height;
|
||||
|
||||
/* The matrix that was current when the clip was set */
|
||||
CoglFixed matrix[16];
|
||||
GList *stack_top;
|
||||
};
|
||||
|
||||
static GList *cogl_clip_stack_top = NULL;
|
||||
static int cogl_clip_stack_depth = 0;
|
||||
|
||||
static void
|
||||
_cogl_clip_stack_add (const CoglClipStackEntry *entry, int depth)
|
||||
struct _CoglClipStackEntryRect
|
||||
{
|
||||
int has_clip_planes = cogl_features_available (COGL_FEATURE_FOUR_CLIP_PLANES);
|
||||
CoglClipStackEntryType type;
|
||||
|
||||
/* If this is the first entry and we support clip planes then use
|
||||
that instead */
|
||||
if (depth == 1 && has_clip_planes)
|
||||
_cogl_set_clip_planes (entry->x_offset,
|
||||
entry->y_offset,
|
||||
entry->width,
|
||||
entry->height);
|
||||
else
|
||||
_cogl_add_stencil_clip (entry->x_offset,
|
||||
entry->y_offset,
|
||||
entry->width,
|
||||
entry->height,
|
||||
depth == (has_clip_planes ? 2 : 1));
|
||||
}
|
||||
/* The rectangle for this clip */
|
||||
CoglFixed x_offset;
|
||||
CoglFixed y_offset;
|
||||
CoglFixed width;
|
||||
CoglFixed height;
|
||||
|
||||
/* The matrix that was current when the clip was set */
|
||||
CoglFixed matrix[16];
|
||||
};
|
||||
|
||||
struct _CoglClipStackEntryPath
|
||||
{
|
||||
CoglClipStackEntryType type;
|
||||
|
||||
/* The matrix that was current when the clip was set */
|
||||
CoglFixed matrix[16];
|
||||
|
||||
CoglFixedVec2 path_nodes_min;
|
||||
CoglFixedVec2 path_nodes_max;
|
||||
|
||||
guint path_size;
|
||||
CoglPathNode path[1];
|
||||
};
|
||||
|
||||
void
|
||||
cogl_clip_set (CoglFixed x_offset,
|
||||
@ -95,10 +104,17 @@ cogl_clip_set (CoglFixed x_offset,
|
||||
CoglFixed width,
|
||||
CoglFixed height)
|
||||
{
|
||||
CoglClipStackEntry *entry = g_slice_new (CoglClipStackEntry);
|
||||
CoglClipStackEntryRect *entry;
|
||||
CoglClipStack *stack;
|
||||
|
||||
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
|
||||
|
||||
stack = (CoglClipStack *) ctx->clip.stacks->data;
|
||||
|
||||
entry = g_slice_new (CoglClipStackEntryRect);
|
||||
|
||||
/* Make a new entry */
|
||||
entry->clear = FALSE;
|
||||
entry->type = COGL_CLIP_STACK_RECT;
|
||||
entry->x_offset = x_offset;
|
||||
entry->y_offset = y_offset;
|
||||
entry->width = width;
|
||||
@ -106,127 +122,231 @@ cogl_clip_set (CoglFixed x_offset,
|
||||
|
||||
cogl_get_modelview_matrix (entry->matrix);
|
||||
|
||||
/* Add the entry to the current clip */
|
||||
_cogl_clip_stack_add (entry, ++cogl_clip_stack_depth);
|
||||
/* Store it in the stack */
|
||||
stack->stack_top = g_list_prepend (stack->stack_top, entry);
|
||||
|
||||
ctx->clip.stack_dirty = TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
cogl_clip_set_from_path_preserve (void)
|
||||
{
|
||||
CoglClipStackEntryPath *entry;
|
||||
CoglClipStack *stack;
|
||||
|
||||
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
|
||||
|
||||
stack = (CoglClipStack *) ctx->clip.stacks->data;
|
||||
|
||||
entry = g_malloc (sizeof (CoglClipStackEntryPath)
|
||||
+ sizeof (CoglPathNode) * (ctx->path_nodes->len - 1));
|
||||
|
||||
entry->type = COGL_CLIP_STACK_PATH;
|
||||
entry->path_nodes_min = ctx->path_nodes_min;
|
||||
entry->path_nodes_max = ctx->path_nodes_max;
|
||||
entry->path_size = ctx->path_nodes->len;
|
||||
memcpy (entry->path, ctx->path_nodes->data,
|
||||
sizeof (CoglPathNode) * ctx->path_nodes->len);
|
||||
|
||||
cogl_get_modelview_matrix (entry->matrix);
|
||||
|
||||
/* Store it in the stack */
|
||||
cogl_clip_stack_top = g_list_prepend (cogl_clip_stack_top, entry);
|
||||
stack->stack_top = g_list_prepend (stack->stack_top, entry);
|
||||
|
||||
ctx->clip.stack_dirty = TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
cogl_clip_set_from_path (void)
|
||||
{
|
||||
cogl_clip_set_from_path_preserve ();
|
||||
|
||||
cogl_path_new ();
|
||||
}
|
||||
|
||||
void
|
||||
cogl_clip_unset (void)
|
||||
{
|
||||
g_return_if_fail (cogl_clip_stack_top != NULL);
|
||||
gpointer entry;
|
||||
CoglClipStack *stack;
|
||||
|
||||
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
|
||||
|
||||
stack = (CoglClipStack *) ctx->clip.stacks->data;
|
||||
|
||||
g_return_if_fail (stack->stack_top != NULL);
|
||||
|
||||
entry = stack->stack_top->data;
|
||||
|
||||
/* Remove the top entry from the stack */
|
||||
g_slice_free (CoglClipStackEntry, cogl_clip_stack_top->data);
|
||||
cogl_clip_stack_top = g_list_delete_link (cogl_clip_stack_top,
|
||||
cogl_clip_stack_top);
|
||||
cogl_clip_stack_depth--;
|
||||
if (*(CoglClipStackEntryType *) entry == COGL_CLIP_STACK_RECT)
|
||||
g_slice_free (CoglClipStackEntryRect, entry);
|
||||
else
|
||||
g_free (entry);
|
||||
|
||||
/* Rebuild the clip */
|
||||
_cogl_clip_stack_rebuild (FALSE);
|
||||
stack->stack_top = g_list_delete_link (stack->stack_top,
|
||||
stack->stack_top);
|
||||
|
||||
ctx->clip.stack_dirty = TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
_cogl_clip_stack_rebuild (gboolean just_stencil)
|
||||
_cogl_clip_stack_rebuild (void)
|
||||
{
|
||||
int has_clip_planes = cogl_features_available (COGL_FEATURE_FOUR_CLIP_PLANES);
|
||||
gboolean using_clip_planes = FALSE;
|
||||
gboolean using_stencil_buffer = FALSE;
|
||||
GList *node;
|
||||
int depth = 0;
|
||||
CoglClipStack *stack;
|
||||
|
||||
/* Disable clip planes if the stack is empty */
|
||||
if (has_clip_planes && cogl_clip_stack_depth < 1)
|
||||
_cogl_disable_clip_planes ();
|
||||
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
|
||||
|
||||
/* Disable the stencil buffer if there isn't enough entries */
|
||||
if (cogl_clip_stack_depth < (has_clip_planes ? 2 : 1))
|
||||
_cogl_disable_stencil_buffer ();
|
||||
stack = (CoglClipStack *) ctx->clip.stacks->data;
|
||||
|
||||
ctx->clip.stack_dirty = FALSE;
|
||||
ctx->clip.stencil_used = FALSE;
|
||||
|
||||
_cogl_disable_clip_planes ();
|
||||
_cogl_disable_stencil_buffer ();
|
||||
|
||||
/* If the stack is empty then there's nothing else to do */
|
||||
if (stack->stack_top == NULL)
|
||||
return;
|
||||
|
||||
/* Find the bottom of the stack */
|
||||
for (node = cogl_clip_stack_top; depth < cogl_clip_stack_depth - 1;
|
||||
node = node->next)
|
||||
depth++;
|
||||
for (node = stack->stack_top; node->next; node = node->next);
|
||||
|
||||
/* Re-add every entry from the bottom of the stack up */
|
||||
depth = 1;
|
||||
for (; depth <= cogl_clip_stack_depth; node = node->prev, depth++)
|
||||
if (!just_stencil || !has_clip_planes || depth > 1)
|
||||
{
|
||||
const CoglClipStackEntry *entry = (CoglClipStackEntry *) node->data;
|
||||
cogl_push_matrix ();
|
||||
_cogl_set_matrix (entry->matrix);
|
||||
_cogl_clip_stack_add (entry, depth);
|
||||
cogl_pop_matrix ();
|
||||
}
|
||||
for (; node; node = node->prev)
|
||||
{
|
||||
gpointer entry = node->data;
|
||||
|
||||
if (*(CoglClipStackEntryType *) entry == COGL_CLIP_STACK_PATH)
|
||||
{
|
||||
CoglClipStackEntryPath *path = (CoglClipStackEntryPath *) entry;
|
||||
|
||||
cogl_push_matrix ();
|
||||
_cogl_set_matrix (path->matrix);
|
||||
|
||||
_cogl_add_path_to_stencil_buffer (path->path_nodes_min,
|
||||
path->path_nodes_max,
|
||||
path->path_size,
|
||||
path->path,
|
||||
using_stencil_buffer);
|
||||
|
||||
cogl_pop_matrix ();
|
||||
|
||||
using_stencil_buffer = TRUE;
|
||||
|
||||
/* We can't use clip planes any more */
|
||||
has_clip_planes = FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
CoglClipStackEntryRect *rect = (CoglClipStackEntryRect *) entry;
|
||||
|
||||
cogl_push_matrix ();
|
||||
_cogl_set_matrix (rect->matrix);
|
||||
|
||||
/* If this is the first entry and we support clip planes then use
|
||||
that instead */
|
||||
if (has_clip_planes)
|
||||
{
|
||||
_cogl_set_clip_planes (rect->x_offset,
|
||||
rect->y_offset,
|
||||
rect->width,
|
||||
rect->height);
|
||||
using_clip_planes = TRUE;
|
||||
/* We can't use clip planes a second time */
|
||||
has_clip_planes = FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
_cogl_add_stencil_clip (rect->x_offset,
|
||||
rect->y_offset,
|
||||
rect->width,
|
||||
rect->height,
|
||||
!using_stencil_buffer);
|
||||
using_stencil_buffer = TRUE;
|
||||
}
|
||||
|
||||
cogl_pop_matrix ();
|
||||
}
|
||||
}
|
||||
|
||||
/* Enabling clip planes is delayed to now so that they won't affect
|
||||
setting up the stencil buffer */
|
||||
if (using_clip_planes)
|
||||
_cogl_enable_clip_planes ();
|
||||
|
||||
ctx->clip.stencil_used = using_stencil_buffer;
|
||||
}
|
||||
|
||||
void
|
||||
_cogl_clip_stack_merge (void)
|
||||
cogl_clip_ensure (void)
|
||||
{
|
||||
GList *node = cogl_clip_stack_top;
|
||||
int i;
|
||||
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
|
||||
|
||||
/* Merge the current clip stack on top of whatever is in the stencil
|
||||
buffer */
|
||||
if (cogl_clip_stack_depth)
|
||||
{
|
||||
for (i = 0; i < cogl_clip_stack_depth - 1; i++)
|
||||
node = node->next;
|
||||
|
||||
/* Skip the first entry if we have clipping planes */
|
||||
if (cogl_features_available (COGL_FEATURE_FOUR_CLIP_PLANES))
|
||||
node = node->prev;
|
||||
|
||||
while (node)
|
||||
{
|
||||
const CoglClipStackEntry *entry = (CoglClipStackEntry *) node->data;
|
||||
cogl_push_matrix ();
|
||||
_cogl_set_matrix (entry->matrix);
|
||||
_cogl_clip_stack_add (entry, 3);
|
||||
cogl_pop_matrix ();
|
||||
|
||||
node = node->prev;
|
||||
}
|
||||
}
|
||||
if (ctx->clip.stack_dirty)
|
||||
_cogl_clip_stack_rebuild ();
|
||||
}
|
||||
|
||||
void
|
||||
cogl_clip_stack_save (void)
|
||||
{
|
||||
CoglClipStackEntry *entry = g_slice_new (CoglClipStackEntry);
|
||||
CoglClipStack *stack;
|
||||
|
||||
/* Push an entry into the stack to mark that it should be cleared */
|
||||
entry->clear = TRUE;
|
||||
cogl_clip_stack_top = g_list_prepend (cogl_clip_stack_top, entry);
|
||||
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
|
||||
|
||||
/* Reset the depth to zero */
|
||||
cogl_clip_stack_depth = 0;
|
||||
stack = g_slice_new (CoglClipStack);
|
||||
stack->stack_top = NULL;
|
||||
|
||||
/* Rebuilding the stack will now disabling all clipping */
|
||||
_cogl_clip_stack_rebuild (FALSE);
|
||||
ctx->clip.stacks = g_slist_prepend (ctx->clip.stacks, stack);
|
||||
|
||||
ctx->clip.stack_dirty = TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
cogl_clip_stack_restore (void)
|
||||
{
|
||||
GList *node;
|
||||
CoglClipStack *stack;
|
||||
|
||||
/* The top of the stack should be a clear marker */
|
||||
g_assert (cogl_clip_stack_top);
|
||||
g_assert (((CoglClipStackEntry *) cogl_clip_stack_top->data)->clear);
|
||||
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
|
||||
|
||||
/* Remove the top entry */
|
||||
g_slice_free (CoglClipStackEntry, cogl_clip_stack_top->data);
|
||||
cogl_clip_stack_top = g_list_delete_link (cogl_clip_stack_top,
|
||||
cogl_clip_stack_top);
|
||||
g_return_if_fail (ctx->clip.stacks != NULL);
|
||||
|
||||
/* Recalculate the depth of the stack */
|
||||
cogl_clip_stack_depth = 0;
|
||||
for (node = cogl_clip_stack_top;
|
||||
node && !((CoglClipStackEntry *) node->data)->clear;
|
||||
node = node->next)
|
||||
cogl_clip_stack_depth++;
|
||||
stack = (CoglClipStack *) ctx->clip.stacks->data;
|
||||
|
||||
_cogl_clip_stack_rebuild (FALSE);
|
||||
/* Empty the current stack */
|
||||
while (stack->stack_top)
|
||||
cogl_clip_unset ();
|
||||
|
||||
/* Revert to an old stack */
|
||||
g_slice_free (CoglClipStack, stack);
|
||||
ctx->clip.stacks = g_slist_delete_link (ctx->clip.stacks,
|
||||
ctx->clip.stacks);
|
||||
|
||||
ctx->clip.stack_dirty = TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
_cogl_clip_stack_state_init (void)
|
||||
{
|
||||
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
|
||||
|
||||
ctx->clip.stacks = NULL;
|
||||
ctx->clip.stack_dirty = TRUE;
|
||||
|
||||
/* Add an intial stack */
|
||||
cogl_clip_stack_save ();
|
||||
}
|
||||
|
||||
void
|
||||
_cogl_clip_stack_state_destroy (void)
|
||||
{
|
||||
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
|
||||
|
||||
/* Destroy all of the stacks */
|
||||
while (ctx->clip.stacks)
|
||||
cogl_clip_stack_restore ();
|
||||
}
|
||||
|
@ -26,7 +26,20 @@
|
||||
#ifndef __COGL_CLIP_STACK_H
|
||||
#define __COGL_CLIP_STACK_H
|
||||
|
||||
void _cogl_clip_stack_rebuild (gboolean just_stencil);
|
||||
typedef struct _CoglClipStackState CoglClipStackState;
|
||||
|
||||
struct _CoglClipStackState
|
||||
{
|
||||
/* Stack of stacks */
|
||||
GSList *stacks;
|
||||
|
||||
gboolean stack_dirty;
|
||||
gboolean stencil_used;
|
||||
};
|
||||
|
||||
void _cogl_clip_stack_state_init (void);
|
||||
void _cogl_clip_stack_state_destroy (void);
|
||||
void _cogl_clip_stack_rebuild (void);
|
||||
void _cogl_clip_stack_merge (void);
|
||||
|
||||
#endif /* __COGL_CLIP_STACK_H */
|
||||
|
@ -37,8 +37,8 @@
|
||||
#define _COGL_MAX_BEZ_RECURSE_DEPTH 16
|
||||
|
||||
/* these are defined in the particular backend(float in gl vs fixed in gles)*/
|
||||
void _cogl_path_clear_nodes ();
|
||||
void _cogl_path_add_node (CoglFixed x,
|
||||
void _cogl_path_add_node (gboolean new_sub_path,
|
||||
CoglFixed x,
|
||||
CoglFixed y);
|
||||
void _cogl_path_fill_nodes ();
|
||||
void _cogl_path_stroke_nodes ();
|
||||
@ -56,6 +56,8 @@ cogl_rectangle (gint x,
|
||||
guint width,
|
||||
guint height)
|
||||
{
|
||||
cogl_clip_ensure ();
|
||||
|
||||
_cogl_rectangle (x, y, width, height);
|
||||
}
|
||||
|
||||
@ -65,27 +67,49 @@ cogl_rectanglex (CoglFixed x,
|
||||
CoglFixed width,
|
||||
CoglFixed height)
|
||||
{
|
||||
cogl_clip_ensure ();
|
||||
|
||||
_cogl_rectanglex (x, y, width, height);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
cogl_path_fill (void)
|
||||
{
|
||||
cogl_path_fill_preserve ();
|
||||
|
||||
cogl_path_new ();
|
||||
}
|
||||
|
||||
void
|
||||
cogl_path_fill_preserve (void)
|
||||
{
|
||||
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
|
||||
|
||||
if (ctx->path_nodes_size == 0)
|
||||
cogl_clip_ensure ();
|
||||
|
||||
if (ctx->path_nodes->len == 0)
|
||||
return;
|
||||
|
||||
_cogl_path_fill_nodes();
|
||||
_cogl_path_fill_nodes ();
|
||||
}
|
||||
|
||||
void
|
||||
cogl_path_stroke (void)
|
||||
{
|
||||
cogl_path_stroke_preserve ();
|
||||
|
||||
cogl_path_new ();
|
||||
}
|
||||
|
||||
void
|
||||
cogl_path_stroke_preserve (void)
|
||||
{
|
||||
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
|
||||
|
||||
if (ctx->path_nodes_size == 0)
|
||||
cogl_clip_ensure ();
|
||||
|
||||
if (ctx->path_nodes->len == 0)
|
||||
return;
|
||||
|
||||
_cogl_path_stroke_nodes();
|
||||
@ -99,11 +123,7 @@ cogl_path_move_to (CoglFixed x,
|
||||
|
||||
/* FIXME: handle multiple contours maybe? */
|
||||
|
||||
/* at the moment, a move_to is an implicit instruction to create
|
||||
* a new path.
|
||||
*/
|
||||
_cogl_path_clear_nodes ();
|
||||
_cogl_path_add_node (x, y);
|
||||
_cogl_path_add_node (TRUE, x, y);
|
||||
|
||||
ctx->path_start.x = x;
|
||||
ctx->path_start.y = y;
|
||||
@ -127,7 +147,7 @@ cogl_path_line_to (CoglFixed x,
|
||||
{
|
||||
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
|
||||
|
||||
_cogl_path_add_node (x, y);
|
||||
_cogl_path_add_node (FALSE, x, y);
|
||||
|
||||
ctx->path_pen.x = x;
|
||||
ctx->path_pen.y = y;
|
||||
@ -148,10 +168,17 @@ cogl_path_close (void)
|
||||
{
|
||||
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
|
||||
|
||||
_cogl_path_add_node (ctx->path_start.x, ctx->path_start.y);
|
||||
_cogl_path_add_node (FALSE, ctx->path_start.x, ctx->path_start.y);
|
||||
ctx->path_pen = ctx->path_start;
|
||||
}
|
||||
|
||||
void
|
||||
cogl_path_new (void)
|
||||
{
|
||||
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
|
||||
|
||||
g_array_set_size (ctx->path_nodes, 0);
|
||||
}
|
||||
|
||||
void
|
||||
cogl_path_line (CoglFixed x1,
|
||||
@ -427,7 +454,7 @@ _cogl_path_bezier3_sub (CoglBezCubic *cubic)
|
||||
if (cindex == 0)
|
||||
return;
|
||||
|
||||
_cogl_path_add_node (c->p4.x, c->p4.y);
|
||||
_cogl_path_add_node (FALSE, c->p4.x, c->p4.y);
|
||||
|
||||
--cindex;
|
||||
|
||||
@ -492,7 +519,7 @@ cogl_path_curve_to (CoglFixed x1,
|
||||
_cogl_path_bezier3_sub (&cubic);
|
||||
|
||||
/* Add last point */
|
||||
_cogl_path_add_node (cubic.p4.x, cubic.p4.y);
|
||||
_cogl_path_add_node (FALSE, cubic.p4.x, cubic.p4.y);
|
||||
ctx->path_pen = cubic.p4;
|
||||
}
|
||||
|
||||
@ -559,7 +586,7 @@ _cogl_path_bezier2_sub (CoglBezQuad *quad)
|
||||
{
|
||||
/* Add subdivision point (skip last) */
|
||||
if (qindex == 0) return;
|
||||
_cogl_path_add_node (q->p3.x, q->p3.y);
|
||||
_cogl_path_add_node (FALSE, q->p3.x, q->p3.y);
|
||||
--qindex; continue;
|
||||
}
|
||||
|
||||
@ -607,7 +634,7 @@ cogl_path_curve2_to (CoglFixed x1,
|
||||
_cogl_path_bezier2_sub (&quad);
|
||||
|
||||
/* Add last point */
|
||||
_cogl_path_add_node (quad.p3.x, quad.p3.y);
|
||||
_cogl_path_add_node (FALSE, quad.p3.x, quad.p3.y);
|
||||
ctx->path_pen = quad.p3;
|
||||
}
|
||||
|
||||
|
@ -29,6 +29,7 @@
|
||||
typedef struct _CoglFixedVec2 CoglFixedVec2;
|
||||
typedef struct _CoglBezQuad CoglBezQuad;
|
||||
typedef struct _CoglBezCubic CoglBezCubic;
|
||||
typedef struct _CoglPathNode CoglPathNode;
|
||||
|
||||
struct _CoglFixedVec2
|
||||
{
|
||||
@ -37,13 +38,32 @@ struct _CoglFixedVec2
|
||||
};
|
||||
|
||||
#ifdef CLUTTER_COGL_HAS_GL
|
||||
|
||||
typedef struct _CoglFloatVec2 CoglFloatVec2;
|
||||
|
||||
struct _CoglFloatVec2
|
||||
{
|
||||
GLfloat x;
|
||||
GLfloat y;
|
||||
};
|
||||
#endif
|
||||
|
||||
struct _CoglPathNode
|
||||
{
|
||||
GLfloat x;
|
||||
GLfloat y;
|
||||
guint path_size;
|
||||
};
|
||||
|
||||
#else /* CLUTTER_COGL_HAS_GL */
|
||||
|
||||
struct _CoglPathNode
|
||||
{
|
||||
GLfixed x;
|
||||
GLfixed y;
|
||||
guint path_size;
|
||||
};
|
||||
|
||||
#endif /* CLUTTER_COGL_HAS_GL */
|
||||
|
||||
struct _CoglBezQuad
|
||||
{
|
||||
|
@ -29,9 +29,12 @@ cogl_rotatex
|
||||
cogl_rotate
|
||||
<SUBSECTION>
|
||||
cogl_clip_set
|
||||
cogl_clip_set_from_path
|
||||
cogl_clip_set_from_path_preserve
|
||||
cogl_clip_unset
|
||||
cogl_clip_stack_save
|
||||
cogl_clip_stack_restore
|
||||
cogl_clip_ensure
|
||||
<SUBSECTION>
|
||||
cogl_enable_depth_test
|
||||
cogl_enable_backface_culling
|
||||
@ -63,6 +66,7 @@ cogl_util_next_p2
|
||||
<SECTION>
|
||||
<FILE>cogl-primitives</FILE>
|
||||
<TITLE>Primitives</TITLE>
|
||||
cogl_path_new
|
||||
cogl_path_move_to
|
||||
cogl_path_close
|
||||
cogl_path_line_to
|
||||
@ -80,7 +84,9 @@ cogl_path_ellipse
|
||||
|
||||
<SUBSECTION>
|
||||
cogl_path_fill
|
||||
cogl_path_fill_preserve
|
||||
cogl_path_stroke
|
||||
cogl_path_stroke_preserve
|
||||
cogl_set_source_color
|
||||
cogl_set_source_color4ub
|
||||
cogl_set_source_color4x
|
||||
|
@ -52,9 +52,8 @@ cogl_create_context ()
|
||||
_context->enable_flags = 0;
|
||||
_context->color_alpha = 255;
|
||||
|
||||
_context->path_nodes = NULL;
|
||||
_context->path_nodes_cap = 0;
|
||||
_context->path_nodes_size = 0;
|
||||
_context->path_nodes = g_array_new (FALSE, FALSE, sizeof (CoglPathNode));
|
||||
_context->last_path = 0;
|
||||
|
||||
_context->texture_handles = NULL;
|
||||
_context->texture_vertices = g_array_new (FALSE, FALSE,
|
||||
@ -123,6 +122,9 @@ cogl_create_context ()
|
||||
GE( glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) );
|
||||
cogl_enable (0);
|
||||
|
||||
/* Initialise the clip stack */
|
||||
_cogl_clip_stack_state_init ();
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@ -132,6 +134,11 @@ cogl_destroy_context ()
|
||||
if (_context == NULL)
|
||||
return;
|
||||
|
||||
_cogl_clip_stack_state_destroy ();
|
||||
|
||||
if (_context->path_nodes)
|
||||
g_array_free (_context->path_nodes, TRUE);
|
||||
|
||||
if (_context->texture_handles)
|
||||
g_array_free (_context->texture_handles, TRUE);
|
||||
if (_context->fbo_handles)
|
||||
|
@ -27,6 +27,7 @@
|
||||
#define __COGL_CONTEXT_H
|
||||
|
||||
#include "cogl-primitives.h"
|
||||
#include "cogl-clip-stack.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
@ -40,7 +41,6 @@ typedef struct
|
||||
/* Features cache */
|
||||
CoglFeatureFlags feature_flags;
|
||||
gboolean features_cached;
|
||||
GLint num_stencil_bits;
|
||||
|
||||
/* Enable cache */
|
||||
gulong enable_flags;
|
||||
@ -53,9 +53,8 @@ typedef struct
|
||||
/* Primitives */
|
||||
CoglFixedVec2 path_start;
|
||||
CoglFixedVec2 path_pen;
|
||||
CoglFloatVec2 *path_nodes;
|
||||
guint path_nodes_cap;
|
||||
guint path_nodes_size;
|
||||
GArray *path_nodes;
|
||||
guint last_path;
|
||||
CoglFixedVec2 path_nodes_min;
|
||||
CoglFixedVec2 path_nodes_max;
|
||||
|
||||
@ -70,6 +69,7 @@ typedef struct
|
||||
can be flushed */
|
||||
GLuint texture_current;
|
||||
GLenum texture_target;
|
||||
GLenum texture_wrap_mode;
|
||||
|
||||
/* Framebuffer objects */
|
||||
GArray *fbo_handles;
|
||||
@ -81,6 +81,9 @@ typedef struct
|
||||
/* Programs */
|
||||
GArray *program_handles;
|
||||
|
||||
/* Clip stack */
|
||||
CoglClipStackState clip;
|
||||
|
||||
/* Mesh */
|
||||
GArray *mesh_handles;
|
||||
|
||||
|
@ -70,43 +70,26 @@ _cogl_rectanglex (CoglFixed x,
|
||||
}
|
||||
|
||||
void
|
||||
_cogl_path_clear_nodes ()
|
||||
{
|
||||
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
|
||||
|
||||
if (ctx->path_nodes)
|
||||
g_free(ctx->path_nodes);
|
||||
|
||||
ctx->path_nodes = (CoglFloatVec2*) g_malloc (2 * sizeof(CoglFloatVec2));
|
||||
ctx->path_nodes_size = 0;
|
||||
ctx->path_nodes_cap = 2;
|
||||
}
|
||||
|
||||
void
|
||||
_cogl_path_add_node (CoglFixed x,
|
||||
_cogl_path_add_node (gboolean new_sub_path,
|
||||
CoglFixed x,
|
||||
CoglFixed y)
|
||||
{
|
||||
CoglFloatVec2 *new_nodes = NULL;
|
||||
CoglPathNode new_node;
|
||||
|
||||
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
|
||||
|
||||
if (ctx->path_nodes_size == ctx->path_nodes_cap)
|
||||
{
|
||||
new_nodes = g_realloc (ctx->path_nodes,
|
||||
2 * ctx->path_nodes_cap
|
||||
* sizeof (CoglFloatVec2));
|
||||
new_node.x = COGL_FIXED_TO_FLOAT (x);
|
||||
new_node.y = COGL_FIXED_TO_FLOAT (y);
|
||||
new_node.path_size = 0;
|
||||
|
||||
if (new_nodes == NULL) return;
|
||||
if (new_sub_path || ctx->path_nodes->len == 0)
|
||||
ctx->last_path = ctx->path_nodes->len;
|
||||
|
||||
ctx->path_nodes = new_nodes;
|
||||
ctx->path_nodes_cap *= 2;
|
||||
}
|
||||
g_array_append_val (ctx->path_nodes, new_node);
|
||||
|
||||
ctx->path_nodes [ctx->path_nodes_size] .x = COGL_FIXED_TO_FLOAT (x);
|
||||
ctx->path_nodes [ctx->path_nodes_size] .y = COGL_FIXED_TO_FLOAT (y);
|
||||
ctx->path_nodes_size++;
|
||||
g_array_index (ctx->path_nodes, CoglPathNode, ctx->last_path).path_size++;
|
||||
|
||||
if (ctx->path_nodes_size == 1)
|
||||
if (ctx->path_nodes->len == 1)
|
||||
{
|
||||
ctx->path_nodes_min.x = ctx->path_nodes_max.x = x;
|
||||
ctx->path_nodes_min.y = ctx->path_nodes_max.y = y;
|
||||
@ -123,55 +106,158 @@ _cogl_path_add_node (CoglFixed x,
|
||||
void
|
||||
_cogl_path_stroke_nodes ()
|
||||
{
|
||||
guint path_start = 0;
|
||||
|
||||
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
|
||||
|
||||
cogl_enable (COGL_ENABLE_VERTEX_ARRAY
|
||||
| (ctx->color_alpha < 255
|
||||
? COGL_ENABLE_BLEND : 0));
|
||||
|
||||
GE( glVertexPointer (2, GL_FLOAT, 0, ctx->path_nodes) );
|
||||
GE( glDrawArrays (GL_LINE_STRIP, 0, ctx->path_nodes_size) );
|
||||
while (path_start < ctx->path_nodes->len)
|
||||
{
|
||||
CoglPathNode *path = &g_array_index (ctx->path_nodes, CoglPathNode,
|
||||
path_start);
|
||||
|
||||
GE( glVertexPointer (2, GL_FLOAT, sizeof (CoglPathNode),
|
||||
(guchar *) path
|
||||
+ G_STRUCT_OFFSET (CoglPathNode, x)) );
|
||||
GE( glDrawArrays (GL_LINE_STRIP, 0, path->path_size) );
|
||||
|
||||
path_start += path->path_size;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
_cogl_path_get_bounds (CoglFixedVec2 nodes_min,
|
||||
CoglFixedVec2 nodes_max,
|
||||
gint *bounds_x,
|
||||
gint *bounds_y,
|
||||
guint *bounds_w,
|
||||
guint *bounds_h)
|
||||
{
|
||||
*bounds_x = COGL_FIXED_FLOOR (nodes_min.x);
|
||||
*bounds_y = COGL_FIXED_FLOOR (nodes_min.y);
|
||||
*bounds_w = COGL_FIXED_CEIL (nodes_max.x
|
||||
- COGL_FIXED_FROM_INT (*bounds_x));
|
||||
*bounds_h = COGL_FIXED_CEIL (nodes_max.y
|
||||
- COGL_FIXED_FROM_INT (*bounds_y));
|
||||
}
|
||||
|
||||
void
|
||||
_cogl_add_path_to_stencil_buffer (CoglFixedVec2 nodes_min,
|
||||
CoglFixedVec2 nodes_max,
|
||||
guint path_size,
|
||||
CoglPathNode *path,
|
||||
gboolean merge)
|
||||
{
|
||||
guint path_start = 0;
|
||||
guint sub_path_num = 0;
|
||||
gint bounds_x;
|
||||
gint bounds_y;
|
||||
guint bounds_w;
|
||||
guint bounds_h;
|
||||
|
||||
_cogl_path_get_bounds (nodes_min, nodes_max,
|
||||
&bounds_x, &bounds_y, &bounds_w, &bounds_h);
|
||||
|
||||
if (merge)
|
||||
{
|
||||
GE( glStencilMask (2) );
|
||||
GE( glStencilFunc (GL_LEQUAL, 0x2, 0x6) );
|
||||
}
|
||||
else
|
||||
{
|
||||
GE( glClear (GL_STENCIL_BUFFER_BIT) );
|
||||
GE( glStencilMask (1) );
|
||||
GE( glStencilFunc (GL_LEQUAL, 0x1, 0x3) );
|
||||
}
|
||||
|
||||
GE( glEnable (GL_STENCIL_TEST) );
|
||||
GE( glStencilOp (GL_INVERT, GL_INVERT, GL_INVERT) );
|
||||
|
||||
GE( glColorMask (FALSE, FALSE, FALSE, FALSE) );
|
||||
GE( glDepthMask (FALSE) );
|
||||
|
||||
while (path_start < path_size)
|
||||
{
|
||||
cogl_enable (COGL_ENABLE_VERTEX_ARRAY);
|
||||
|
||||
GE( glVertexPointer (2, GL_FLOAT, sizeof (CoglPathNode),
|
||||
(guchar *) path
|
||||
+ G_STRUCT_OFFSET (CoglPathNode, x)) );
|
||||
GE( glDrawArrays (GL_TRIANGLE_FAN, 0, path->path_size) );
|
||||
|
||||
if (sub_path_num > 0)
|
||||
{
|
||||
/* Union the two stencil buffers bits into the least
|
||||
significant bit */
|
||||
GE( glStencilMask (merge ? 6 : 3) );
|
||||
GE( glStencilOp (GL_ZERO, GL_REPLACE, GL_REPLACE) );
|
||||
cogl_rectangle (bounds_x, bounds_y, bounds_w, bounds_h);
|
||||
|
||||
GE( glStencilOp (GL_INVERT, GL_INVERT, GL_INVERT) );
|
||||
}
|
||||
|
||||
GE( glStencilMask (merge ? 4 : 2) );
|
||||
|
||||
path_start += path->path_size;
|
||||
path += path->path_size;
|
||||
sub_path_num++;
|
||||
}
|
||||
|
||||
if (merge)
|
||||
{
|
||||
/* Now we have the new stencil buffer in bit 1 and the old
|
||||
stencil buffer in bit 0 so we need to intersect them */
|
||||
GE( glStencilMask (3) );
|
||||
GE( glStencilFunc (GL_NEVER, 0x2, 0x3) );
|
||||
GE( glStencilOp (GL_DECR, GL_DECR, GL_DECR) );
|
||||
/* Decrement all of the bits twice so that only pixels where the
|
||||
value is 3 will remain */
|
||||
GE( glPushMatrix () );
|
||||
GE( glLoadIdentity () );
|
||||
GE( glMatrixMode (GL_PROJECTION) );
|
||||
GE( glPushMatrix () );
|
||||
GE( glLoadIdentity () );
|
||||
GE( glRecti (-1, 1, 1, -1) );
|
||||
GE( glRecti (-1, 1, 1, -1) );
|
||||
GE( glPopMatrix () );
|
||||
GE( glMatrixMode (GL_MODELVIEW) );
|
||||
GE( glPopMatrix () );
|
||||
}
|
||||
|
||||
GE( glStencilMask (~(GLuint) 0) );
|
||||
GE( glDepthMask (TRUE) );
|
||||
GE( glColorMask (TRUE, TRUE, TRUE, TRUE) );
|
||||
|
||||
GE( glStencilFunc (GL_EQUAL, 0x1, 0x1) );
|
||||
GE( glStencilOp (GL_KEEP, GL_KEEP, GL_KEEP) );
|
||||
}
|
||||
|
||||
void
|
||||
_cogl_path_fill_nodes ()
|
||||
{
|
||||
guint bounds_x;
|
||||
guint bounds_y;
|
||||
gint bounds_x;
|
||||
gint bounds_y;
|
||||
guint bounds_w;
|
||||
guint bounds_h;
|
||||
|
||||
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
|
||||
|
||||
GE( glClear (GL_STENCIL_BUFFER_BIT) );
|
||||
_cogl_add_path_to_stencil_buffer (ctx->path_nodes_min,
|
||||
ctx->path_nodes_max,
|
||||
ctx->path_nodes->len,
|
||||
&g_array_index (ctx->path_nodes,
|
||||
CoglPathNode, 0),
|
||||
ctx->clip.stencil_used);
|
||||
|
||||
GE( glEnable (GL_STENCIL_TEST) );
|
||||
GE( glStencilFunc (GL_NEVER, 0x0, 0x1) );
|
||||
GE( glStencilOp (GL_INVERT, GL_INVERT, GL_INVERT) );
|
||||
|
||||
GE( glStencilMask (1) );
|
||||
|
||||
cogl_enable (COGL_ENABLE_VERTEX_ARRAY
|
||||
| (ctx->color_alpha < 255 ? COGL_ENABLE_BLEND : 0));
|
||||
|
||||
GE( glVertexPointer (2, GL_FLOAT, 0, ctx->path_nodes) );
|
||||
GE( glDrawArrays (GL_TRIANGLE_FAN, 0, ctx->path_nodes_size) );
|
||||
|
||||
GE( glStencilMask (~(GLuint) 0) );
|
||||
|
||||
/* Merge the stencil buffer with any clipping rectangles */
|
||||
_cogl_clip_stack_merge ();
|
||||
|
||||
GE( glStencilFunc (GL_EQUAL, 0x1, 0x1) );
|
||||
GE( glStencilOp (GL_KEEP, GL_KEEP, GL_KEEP) );
|
||||
|
||||
bounds_x = COGL_FIXED_FLOOR (ctx->path_nodes_min.x);
|
||||
bounds_y = COGL_FIXED_FLOOR (ctx->path_nodes_min.y);
|
||||
bounds_w = COGL_FIXED_CEIL (ctx->path_nodes_max.x - ctx->path_nodes_min.x);
|
||||
bounds_h = COGL_FIXED_CEIL (ctx->path_nodes_max.y - ctx->path_nodes_min.y);
|
||||
_cogl_path_get_bounds (ctx->path_nodes_min, ctx->path_nodes_max,
|
||||
&bounds_x, &bounds_y, &bounds_w, &bounds_h);
|
||||
|
||||
cogl_rectangle (bounds_x, bounds_y, bounds_w, bounds_h);
|
||||
|
||||
/* Rebuild the stencil clip */
|
||||
_cogl_clip_stack_rebuild (TRUE);
|
||||
/* The stencil buffer now contains garbage so the clip area needs to
|
||||
be rebuilt */
|
||||
ctx->clip.stack_dirty = TRUE;
|
||||
}
|
||||
|
@ -763,6 +763,29 @@ _cogl_texture_size_supported (GLenum gl_target,
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
_cogl_texture_set_wrap_mode_parameter (CoglTexture *tex,
|
||||
GLenum wrap_mode)
|
||||
{
|
||||
/* Only set the wrap mode if it's different from the current
|
||||
value to avoid too many GL calls */
|
||||
if (tex->wrap_mode != wrap_mode)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < tex->slice_gl_handles->len; i++)
|
||||
{
|
||||
GLuint texnum = g_array_index (tex->slice_gl_handles, GLuint, i);
|
||||
|
||||
GE( glBindTexture (tex->gl_target, texnum) );
|
||||
GE( glTexParameteri (tex->gl_target, GL_TEXTURE_WRAP_S, wrap_mode) );
|
||||
GE( glTexParameteri (tex->gl_target, GL_TEXTURE_WRAP_T, wrap_mode) );
|
||||
}
|
||||
|
||||
tex->wrap_mode = wrap_mode;
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
_cogl_texture_slices_create (CoglTexture *tex)
|
||||
{
|
||||
@ -891,13 +914,8 @@ _cogl_texture_slices_create (CoglTexture *tex)
|
||||
|
||||
g_array_set_size (tex->slice_gl_handles, n_slices);
|
||||
|
||||
|
||||
/* Hardware repeated tiling if supported, else tile in software*/
|
||||
if (cogl_features_available (COGL_FEATURE_TEXTURE_NPOT)
|
||||
&& n_slices == 1)
|
||||
tex->wrap_mode = GL_REPEAT;
|
||||
else
|
||||
tex->wrap_mode = GL_CLAMP_TO_EDGE;
|
||||
/* Wrap mode not yet set */
|
||||
tex->wrap_mode = GL_FALSE;
|
||||
|
||||
/* Generate a "working set" of GL texture objects
|
||||
* (some implementations might supported faster
|
||||
@ -930,11 +948,6 @@ _cogl_texture_slices_create (CoglTexture *tex)
|
||||
GE( glTexParameteri (tex->gl_target, GL_TEXTURE_MIN_FILTER,
|
||||
tex->min_filter) );
|
||||
|
||||
GE( glTexParameteri (tex->gl_target, GL_TEXTURE_WRAP_S,
|
||||
tex->wrap_mode) );
|
||||
GE( glTexParameteri (tex->gl_target, GL_TEXTURE_WRAP_T,
|
||||
tex->wrap_mode) );
|
||||
|
||||
if (tex->auto_mipmap)
|
||||
GE( glTexParameteri (tex->gl_target, GL_GENERATE_MIPMAP,
|
||||
GL_TRUE) );
|
||||
@ -1415,8 +1428,14 @@ cogl_texture_new_from_foreign (GLuint gl_handle,
|
||||
CoglTexSliceSpan x_span;
|
||||
CoglTexSliceSpan y_span;
|
||||
|
||||
/* Allow 2-dimensional textures only */
|
||||
if (gl_target != GL_TEXTURE_2D)
|
||||
/* GL_ARB_texture_rectangle textures are supported if they are
|
||||
created from foreign because some chipsets have trouble with
|
||||
GL_ARB_texture_non_power_of_two. There is no Cogl call to create
|
||||
them directly to emphasize the fact that they don't work fully
|
||||
(for example, no mipmapping and complicated shader support) */
|
||||
|
||||
/* Allow 2-dimensional or rectangle textures only */
|
||||
if (gl_target != GL_TEXTURE_2D && gl_target != CGL_TEXTURE_RECTANGLE_ARB)
|
||||
return COGL_INVALID_HANDLE;
|
||||
|
||||
/* Make sure it is a valid GL texture object */
|
||||
@ -1508,6 +1527,9 @@ cogl_texture_new_from_foreign (GLuint gl_handle,
|
||||
tex->mag_filter = gl_mag_filter;
|
||||
tex->max_waste = 0;
|
||||
|
||||
/* Wrap mode not yet set */
|
||||
tex->wrap_mode = GL_FALSE;
|
||||
|
||||
/* Create slice arrays */
|
||||
tex->slice_x_spans =
|
||||
g_array_sized_new (FALSE, FALSE,
|
||||
@ -1534,23 +1556,6 @@ cogl_texture_new_from_foreign (GLuint gl_handle,
|
||||
|
||||
g_array_append_val (tex->slice_gl_handles, gl_handle);
|
||||
|
||||
/* Force appropriate wrap parameter */
|
||||
if (cogl_features_available (COGL_FEATURE_TEXTURE_NPOT) &&
|
||||
gl_target == GL_TEXTURE_2D)
|
||||
{
|
||||
/* Hardware repeated tiling */
|
||||
tex->wrap_mode = GL_REPEAT;
|
||||
GE( glTexParameteri (tex->gl_target, GL_TEXTURE_WRAP_S, GL_REPEAT) );
|
||||
GE( glTexParameteri (tex->gl_target, GL_TEXTURE_WRAP_T, GL_REPEAT) );
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Any tiling will be done in software */
|
||||
tex->wrap_mode = GL_CLAMP_TO_EDGE;
|
||||
GE( glTexParameteri (tex->gl_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE) );
|
||||
GE( glTexParameteri (tex->gl_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE) );
|
||||
}
|
||||
|
||||
return _cogl_texture_handle_new (tex);
|
||||
}
|
||||
|
||||
@ -1957,6 +1962,14 @@ _cogl_texture_quad_sw (CoglTexture *tex,
|
||||
printf("=== Drawing Tex Quad (Software Tiling Mode) ===\n");
|
||||
#endif
|
||||
|
||||
/* We can't use hardware repeat so we need to set clamp to edge
|
||||
otherwise it might pull in edge pixels from the other side */
|
||||
if (ctx->texture_vertices->len > 0
|
||||
&& ctx->texture_wrap_mode != GL_CLAMP_TO_EDGE)
|
||||
_cogl_texture_flush_vertices ();
|
||||
_cogl_texture_set_wrap_mode_parameter (tex, GL_CLAMP_TO_EDGE);
|
||||
ctx->texture_wrap_mode = GL_CLAMP_TO_EDGE;
|
||||
|
||||
/* If the texture coordinates are backwards then swap both the
|
||||
geometry and texture coordinates so that the texture will be
|
||||
flipped but we can still use the same algorithm to iterate the
|
||||
@ -2026,9 +2039,11 @@ _cogl_texture_quad_sw (CoglTexture *tex,
|
||||
|
||||
/* Normalize texture coordinates to current slice
|
||||
(rectangle texture targets take denormalized) */
|
||||
slice_ty1 /= iter_y.span->size;
|
||||
slice_ty2 /= iter_y.span->size;
|
||||
|
||||
if (tex->gl_target != CGL_TEXTURE_RECTANGLE_ARB)
|
||||
{
|
||||
slice_ty1 /= iter_y.span->size;
|
||||
slice_ty2 /= iter_y.span->size;
|
||||
}
|
||||
|
||||
/* Iterate until whole quad width covered */
|
||||
for (_cogl_span_iter_begin (&iter_x, tex->slice_x_spans,
|
||||
@ -2052,8 +2067,11 @@ _cogl_texture_quad_sw (CoglTexture *tex,
|
||||
|
||||
/* Normalize texture coordinates to current slice
|
||||
(rectangle texture targets take denormalized) */
|
||||
slice_tx1 /= iter_x.span->size;
|
||||
slice_tx2 /= iter_x.span->size;
|
||||
if (tex->gl_target != CGL_TEXTURE_RECTANGLE_ARB)
|
||||
{
|
||||
slice_tx1 /= iter_x.span->size;
|
||||
slice_tx2 /= iter_x.span->size;
|
||||
}
|
||||
|
||||
#if COGL_DEBUG
|
||||
printf("~~~~~ slice (%d,%d)\n", iter_x.index, iter_y.index);
|
||||
@ -2128,6 +2146,7 @@ _cogl_texture_quad_hw (CoglTexture *tex,
|
||||
CoglTexSliceSpan *x_span;
|
||||
CoglTexSliceSpan *y_span;
|
||||
CoglTextureGLVertex *p;
|
||||
GLenum wrap_mode;
|
||||
|
||||
#if COGL_DEBUG
|
||||
printf("=== Drawing Tex Quad (Hardware Tiling Mode) ===\n");
|
||||
@ -2135,15 +2154,31 @@ _cogl_texture_quad_hw (CoglTexture *tex,
|
||||
|
||||
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
|
||||
|
||||
/* If the texture coords are all in the range [0,1] then we want to
|
||||
clamp the coords to the edge otherwise it can pull in edge pixels
|
||||
from the wrong side when scaled */
|
||||
if (tx1 >= 0 && tx1 <= COGL_FIXED_1
|
||||
&& tx2 >= 0 && tx2 <= COGL_FIXED_1
|
||||
&& ty1 >= 0 && ty1 <= COGL_FIXED_1
|
||||
&& ty2 >= 0 && ty2 <= COGL_FIXED_1)
|
||||
wrap_mode = GL_CLAMP_TO_EDGE;
|
||||
else
|
||||
wrap_mode = GL_REPEAT;
|
||||
|
||||
/* Pick and bind opengl texture object */
|
||||
gl_handle = g_array_index (tex->slice_gl_handles, GLuint, 0);
|
||||
|
||||
/* If we're using a different texture from the one already queued
|
||||
then flush the vertices */
|
||||
if (ctx->texture_vertices->len > 0 && gl_handle != ctx->texture_current)
|
||||
if (ctx->texture_vertices->len > 0
|
||||
&& (gl_handle != ctx->texture_current
|
||||
|| ctx->texture_wrap_mode != wrap_mode))
|
||||
_cogl_texture_flush_vertices ();
|
||||
ctx->texture_target = tex->gl_target;
|
||||
ctx->texture_current = gl_handle;
|
||||
ctx->texture_wrap_mode = wrap_mode;
|
||||
|
||||
_cogl_texture_set_wrap_mode_parameter (tex, wrap_mode);
|
||||
|
||||
/* Don't include the waste in the texture coordinates */
|
||||
x_span = &g_array_index (tex->slice_x_spans, CoglTexSliceSpan, 0);
|
||||
@ -2160,6 +2195,15 @@ _cogl_texture_quad_hw (CoglTexture *tex,
|
||||
p = &g_array_index (ctx->texture_vertices, CoglTextureGLVertex,
|
||||
ctx->texture_vertices->len - 6);
|
||||
|
||||
/* Denormalize texture coordinates for rectangle textures */
|
||||
if (tex->gl_target == GL_TEXTURE_RECTANGLE_ARB)
|
||||
{
|
||||
tx1 *= x_span->size;
|
||||
tx2 *= x_span->size;
|
||||
ty1 *= y_span->size;
|
||||
ty2 *= y_span->size;
|
||||
}
|
||||
|
||||
#define CFX_F(x) COGL_FIXED_TO_FLOAT(x)
|
||||
|
||||
p->v[0] = CFX_F (x1); p->v[1] = CFX_F (y2);
|
||||
@ -2191,8 +2235,7 @@ cogl_texture_multiple_rectangles (CoglHandle handle,
|
||||
guint n_rects)
|
||||
{
|
||||
CoglTexture *tex;
|
||||
gulong enable_flags = (COGL_ENABLE_TEXTURE_2D
|
||||
| COGL_ENABLE_VERTEX_ARRAY
|
||||
gulong enable_flags = (COGL_ENABLE_VERTEX_ARRAY
|
||||
| COGL_ENABLE_TEXCOORD_ARRAY);
|
||||
|
||||
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
|
||||
@ -2201,6 +2244,8 @@ cogl_texture_multiple_rectangles (CoglHandle handle,
|
||||
if (!cogl_is_texture (handle))
|
||||
return;
|
||||
|
||||
cogl_clip_ensure ();
|
||||
|
||||
tex = _cogl_texture_pointer_from_handle (handle);
|
||||
|
||||
/* Make sure we got stuff to draw */
|
||||
@ -2211,6 +2256,11 @@ cogl_texture_multiple_rectangles (CoglHandle handle,
|
||||
return;
|
||||
|
||||
/* Prepare GL state */
|
||||
if (tex->gl_target == CGL_TEXTURE_RECTANGLE_ARB)
|
||||
enable_flags |= COGL_ENABLE_TEXTURE_RECT;
|
||||
else
|
||||
enable_flags |= COGL_ENABLE_TEXTURE_2D;
|
||||
|
||||
if (ctx->color_alpha < 255
|
||||
|| tex->bitmap.format & COGL_A_BIT)
|
||||
enable_flags |= COGL_ENABLE_BLEND;
|
||||
@ -2230,7 +2280,8 @@ cogl_texture_multiple_rectangles (CoglHandle handle,
|
||||
NPOT (no waste) or all of the coordinates are in the
|
||||
range [0,1] then we can use hardware tiling */
|
||||
if (tex->slice_gl_handles->len == 1
|
||||
&& (cogl_features_available (COGL_FEATURE_TEXTURE_NPOT)
|
||||
&& ((cogl_features_available (COGL_FEATURE_TEXTURE_NPOT)
|
||||
&& tex->gl_target == GL_TEXTURE_2D)
|
||||
|| (verts[4] >= 0 && verts[4] <= COGL_FIXED_1
|
||||
&& verts[6] >= 0 && verts[6] <= COGL_FIXED_1
|
||||
&& verts[5] >= 0 && verts[5] <= COGL_FIXED_1
|
||||
@ -2292,6 +2343,8 @@ cogl_texture_polygon (CoglHandle handle,
|
||||
if (!cogl_is_texture (handle))
|
||||
return;
|
||||
|
||||
cogl_clip_ensure ();
|
||||
|
||||
tex = _cogl_texture_pointer_from_handle (handle);
|
||||
|
||||
/* The polygon will have artifacts where the slices join if the wrap
|
||||
@ -2321,11 +2374,14 @@ cogl_texture_polygon (CoglHandle handle,
|
||||
p = (CoglTextureGLVertex *) ctx->texture_vertices->data;
|
||||
|
||||
/* Prepare GL state */
|
||||
enable_flags = (COGL_ENABLE_TEXTURE_2D
|
||||
| COGL_ENABLE_VERTEX_ARRAY
|
||||
enable_flags = (COGL_ENABLE_VERTEX_ARRAY
|
||||
| COGL_ENABLE_TEXCOORD_ARRAY
|
||||
| COGL_ENABLE_BLEND);
|
||||
|
||||
if (tex->gl_target == CGL_TEXTURE_RECTANGLE_ARB)
|
||||
enable_flags |= COGL_ENABLE_TEXTURE_RECT;
|
||||
else
|
||||
enable_flags |= COGL_ENABLE_TEXTURE_2D;
|
||||
|
||||
if (ctx->enable_backface_culling)
|
||||
enable_flags |= COGL_ENABLE_BACKFACE_CULLING;
|
||||
@ -2344,15 +2400,7 @@ cogl_texture_polygon (CoglHandle handle,
|
||||
|
||||
/* Temporarily change the wrapping mode on all of the slices to use
|
||||
a transparent border */
|
||||
for (i = 0; i < tex->slice_gl_handles->len; i++)
|
||||
{
|
||||
GE( glBindTexture (tex->gl_target,
|
||||
g_array_index (tex->slice_gl_handles, GLuint, i)) );
|
||||
GE( glTexParameteri (tex->gl_target, GL_TEXTURE_WRAP_S,
|
||||
GL_CLAMP_TO_BORDER) );
|
||||
GE( glTexParameteri (tex->gl_target, GL_TEXTURE_WRAP_T,
|
||||
GL_CLAMP_TO_BORDER) );
|
||||
}
|
||||
_cogl_texture_set_wrap_mode_parameter (tex, GL_CLAMP_TO_BORDER);
|
||||
|
||||
tex_num = 0;
|
||||
|
||||
@ -2375,19 +2423,31 @@ cogl_texture_polygon (CoglHandle handle,
|
||||
OpenGL */
|
||||
for (i = 0; i < n_vertices; i++, p++)
|
||||
{
|
||||
CoglFixed tx, ty;
|
||||
|
||||
#define CFX_F COGL_FIXED_TO_FLOAT
|
||||
|
||||
tx = ((vertices[i].tx
|
||||
- (COGL_FIXED_FROM_INT (x_span->start)
|
||||
/ tex->bitmap.width))
|
||||
* tex->bitmap.width / x_span->size);
|
||||
ty = ((vertices[i].ty
|
||||
- (COGL_FIXED_FROM_INT (y_span->start)
|
||||
/ tex->bitmap.height))
|
||||
* tex->bitmap.height / y_span->size);
|
||||
|
||||
/* Scale the coordinates up for rectangle textures */
|
||||
if (tex->gl_target == CGL_TEXTURE_RECTANGLE_ARB)
|
||||
{
|
||||
tx *= x_span->size;
|
||||
ty *= y_span->size;
|
||||
}
|
||||
|
||||
p->v[0] = CFX_F(vertices[i].x);
|
||||
p->v[1] = CFX_F(vertices[i].y);
|
||||
p->v[2] = CFX_F(vertices[i].z);
|
||||
p->t[0] = CFX_F((vertices[i].tx
|
||||
- (COGL_FIXED_FROM_INT (x_span->start)
|
||||
/ tex->bitmap.width))
|
||||
* tex->bitmap.width / x_span->size);
|
||||
p->t[1] = CFX_F((vertices[i].ty
|
||||
- (COGL_FIXED_FROM_INT (y_span->start)
|
||||
/ tex->bitmap.height))
|
||||
* tex->bitmap.height / y_span->size);
|
||||
p->t[0] = CFX_F(tx);
|
||||
p->t[1] = CFX_F(ty);
|
||||
p->c[0] = cogl_color_get_red_byte(&vertices[i].color);
|
||||
p->c[1] = cogl_color_get_green_byte(&vertices[i].color);
|
||||
p->c[2] = cogl_color_get_blue_byte(&vertices[i].color);
|
||||
@ -2401,13 +2461,4 @@ cogl_texture_polygon (CoglHandle handle,
|
||||
GE( glDrawArrays (GL_TRIANGLE_FAN, 0, n_vertices) );
|
||||
}
|
||||
}
|
||||
|
||||
/* Restore the wrapping mode */
|
||||
for (i = 0; i < tex->slice_gl_handles->len; i++)
|
||||
{
|
||||
GE( glBindTexture (tex->gl_target,
|
||||
g_array_index (tex->slice_gl_handles, GLuint, i)) );
|
||||
GE( glTexParameteri (tex->gl_target, GL_TEXTURE_WRAP_S, tex->wrap_mode) );
|
||||
GE( glTexParameteri (tex->gl_target, GL_TEXTURE_WRAP_T, tex->wrap_mode) );
|
||||
}
|
||||
}
|
||||
|
167
gl/cogl.c
167
gl/cogl.c
@ -319,6 +319,12 @@ cogl_enable (gulong flags)
|
||||
COGL_ENABLE_BACKFACE_CULLING,
|
||||
GL_CULL_FACE);
|
||||
|
||||
#ifdef GL_TEXTURE_RECTANGLE_ARB
|
||||
cogl_toggle_flag (ctx, flags,
|
||||
COGL_ENABLE_TEXTURE_RECT,
|
||||
GL_TEXTURE_RECTANGLE_ARB);
|
||||
#endif
|
||||
|
||||
cogl_toggle_client_flag (ctx, flags,
|
||||
COGL_ENABLE_VERTEX_ARRAY,
|
||||
GL_VERTEX_ARRAY);
|
||||
@ -457,8 +463,6 @@ set_clip_plane (GLint plane_num,
|
||||
GE( glClipPlane (plane_num, plane) );
|
||||
|
||||
GE( glPopMatrix () );
|
||||
|
||||
GE( glEnable (plane_num) );
|
||||
}
|
||||
|
||||
void
|
||||
@ -513,15 +517,6 @@ _cogl_set_clip_planes (CoglFixed x_offset,
|
||||
set_clip_plane (GL_CLIP_PLANE3, vertex_bl, vertex_tl);
|
||||
}
|
||||
|
||||
static int
|
||||
compare_y_coordinate (const void *a, const void *b)
|
||||
{
|
||||
GLfloat ay = ((const GLfloat *) a)[1];
|
||||
GLfloat by = ((const GLfloat *) b)[1];
|
||||
|
||||
return ay < by ? -1 : ay > by ? 1 : 0;
|
||||
}
|
||||
|
||||
void
|
||||
_cogl_add_stencil_clip (CoglFixed x_offset,
|
||||
CoglFixed y_offset,
|
||||
@ -529,19 +524,8 @@ _cogl_add_stencil_clip (CoglFixed x_offset,
|
||||
CoglFixed height,
|
||||
gboolean first)
|
||||
{
|
||||
gboolean has_clip_planes
|
||||
= cogl_features_available (COGL_FEATURE_FOUR_CLIP_PLANES);
|
||||
|
||||
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
|
||||
|
||||
if (has_clip_planes)
|
||||
{
|
||||
GE( glDisable (GL_CLIP_PLANE3) );
|
||||
GE( glDisable (GL_CLIP_PLANE2) );
|
||||
GE( glDisable (GL_CLIP_PLANE1) );
|
||||
GE( glDisable (GL_CLIP_PLANE0) );
|
||||
}
|
||||
|
||||
if (first)
|
||||
{
|
||||
GE( glEnable (GL_STENCIL_TEST) );
|
||||
@ -558,7 +542,7 @@ _cogl_add_stencil_clip (CoglFixed x_offset,
|
||||
COGL_FIXED_TO_FLOAT (x_offset + width),
|
||||
COGL_FIXED_TO_FLOAT (y_offset + height)) );
|
||||
}
|
||||
else if (ctx->num_stencil_bits > 1)
|
||||
else
|
||||
{
|
||||
/* Add one to every pixel of the stencil buffer in the
|
||||
rectangle */
|
||||
@ -583,127 +567,6 @@ _cogl_add_stencil_clip (CoglFixed x_offset,
|
||||
GE( glMatrixMode (GL_MODELVIEW) );
|
||||
GE( glPopMatrix () );
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Slower fallback if there is exactly one stencil bit. This
|
||||
tries to draw enough triangles to tessalate around the
|
||||
rectangle so that it can subtract from the stencil buffer for
|
||||
every pixel in the screen except those in the rectangle */
|
||||
GLfloat modelview[16], projection[16];
|
||||
GLfloat temp_point[4];
|
||||
GLfloat left_edge, right_edge, bottom_edge, top_edge;
|
||||
int i;
|
||||
GLfloat points[16] =
|
||||
{
|
||||
COGL_FIXED_TO_FLOAT (x_offset),
|
||||
COGL_FIXED_TO_FLOAT (y_offset),
|
||||
0, 1,
|
||||
COGL_FIXED_TO_FLOAT (x_offset + width),
|
||||
COGL_FIXED_TO_FLOAT (y_offset),
|
||||
0, 1,
|
||||
COGL_FIXED_TO_FLOAT (x_offset),
|
||||
COGL_FIXED_TO_FLOAT (y_offset + height),
|
||||
0, 1,
|
||||
COGL_FIXED_TO_FLOAT (x_offset + width),
|
||||
COGL_FIXED_TO_FLOAT (y_offset + height),
|
||||
0, 1
|
||||
};
|
||||
|
||||
GE( glGetFloatv (GL_MODELVIEW_MATRIX, modelview) );
|
||||
GE( glGetFloatv (GL_PROJECTION_MATRIX, projection) );
|
||||
|
||||
/* Project all of the vertices into screen coordinates */
|
||||
for (i = 0; i < 4; i++)
|
||||
project_vertex (modelview, projection, points + i * 4);
|
||||
|
||||
/* Sort the points by y coordinate */
|
||||
qsort (points, 4, sizeof (GLfloat) * 4, compare_y_coordinate);
|
||||
|
||||
/* Put the bottom two pairs and the top two pairs in
|
||||
left-right order */
|
||||
if (points[0] > points[4])
|
||||
{
|
||||
memcpy (temp_point, points, sizeof (GLfloat) * 4);
|
||||
memcpy (points, points + 4, sizeof (GLfloat) * 4);
|
||||
memcpy (points + 4, temp_point, sizeof (GLfloat) * 4);
|
||||
}
|
||||
if (points[8] > points[12])
|
||||
{
|
||||
memcpy (temp_point, points + 8, sizeof (GLfloat) * 4);
|
||||
memcpy (points + 8, points + 12, sizeof (GLfloat) * 4);
|
||||
memcpy (points + 12, temp_point, sizeof (GLfloat) * 4);
|
||||
}
|
||||
|
||||
/* If the clip rect goes outside of the screen then use the
|
||||
extents of the rect instead */
|
||||
left_edge = MIN (-1.0f, MIN (points[0], points[8]));
|
||||
right_edge = MAX ( 1.0f, MAX (points[4], points[12]));
|
||||
bottom_edge = MIN (-1.0f, MIN (points[1], points[5]));
|
||||
top_edge = MAX ( 1.0f, MAX (points[9], points[13]));
|
||||
|
||||
/* Using the identity matrix for the projection and
|
||||
modelview matrix, draw the triangles around the inner
|
||||
rectangle */
|
||||
GE( glStencilFunc (GL_NEVER, 0x1, 0x1) );
|
||||
GE( glStencilOp (GL_ZERO, GL_ZERO, GL_ZERO) );
|
||||
GE( glPushMatrix () );
|
||||
GE( glLoadIdentity () );
|
||||
GE( glMatrixMode (GL_PROJECTION) );
|
||||
GE( glPushMatrix () );
|
||||
GE( glLoadIdentity () );
|
||||
|
||||
/* Clear the left side */
|
||||
glBegin (GL_TRIANGLE_STRIP);
|
||||
glVertex2f (left_edge, bottom_edge);
|
||||
glVertex2fv (points);
|
||||
glVertex2f (left_edge, points[1]);
|
||||
glVertex2fv (points + 8);
|
||||
glVertex2f (left_edge, points[9]);
|
||||
glVertex2f (left_edge, top_edge);
|
||||
glEnd ();
|
||||
|
||||
/* Clear the right side */
|
||||
glBegin (GL_TRIANGLE_STRIP);
|
||||
glVertex2f (right_edge, top_edge);
|
||||
glVertex2fv (points + 12);
|
||||
glVertex2f (right_edge, points[13]);
|
||||
glVertex2fv (points + 4);
|
||||
glVertex2f (right_edge, points[5]);
|
||||
glVertex2f (right_edge, bottom_edge);
|
||||
glEnd ();
|
||||
|
||||
/* Clear the top side */
|
||||
glBegin (GL_TRIANGLE_STRIP);
|
||||
glVertex2f (left_edge, top_edge);
|
||||
glVertex2fv (points + 8);
|
||||
glVertex2f (points[8], top_edge);
|
||||
glVertex2fv (points + 12);
|
||||
glVertex2f (points[12], top_edge);
|
||||
glVertex2f (right_edge, top_edge);
|
||||
glEnd ();
|
||||
|
||||
/* Clear the bottom side */
|
||||
glBegin (GL_TRIANGLE_STRIP);
|
||||
glVertex2f (left_edge, bottom_edge);
|
||||
glVertex2fv (points);
|
||||
glVertex2f (points[0], bottom_edge);
|
||||
glVertex2fv (points + 4);
|
||||
glVertex2f (points[4], bottom_edge);
|
||||
glVertex2f (right_edge, bottom_edge);
|
||||
glEnd ();
|
||||
|
||||
GE( glPopMatrix () );
|
||||
GE( glMatrixMode (GL_MODELVIEW) );
|
||||
GE( glPopMatrix () );
|
||||
}
|
||||
|
||||
if (has_clip_planes)
|
||||
{
|
||||
GE( glEnable (GL_CLIP_PLANE0) );
|
||||
GE( glEnable (GL_CLIP_PLANE1) );
|
||||
GE( glEnable (GL_CLIP_PLANE2) );
|
||||
GE( glEnable (GL_CLIP_PLANE3) );
|
||||
}
|
||||
|
||||
/* Restore the stencil mode */
|
||||
GE( glStencilFunc (GL_EQUAL, 0x1, 0x1) );
|
||||
@ -729,6 +592,15 @@ _cogl_disable_stencil_buffer (void)
|
||||
GE( glDisable (GL_STENCIL_TEST) );
|
||||
}
|
||||
|
||||
void
|
||||
_cogl_enable_clip_planes (void)
|
||||
{
|
||||
GE( glEnable (GL_CLIP_PLANE0) );
|
||||
GE( glEnable (GL_CLIP_PLANE1) );
|
||||
GE( glEnable (GL_CLIP_PLANE2) );
|
||||
GE( glEnable (GL_CLIP_PLANE3) );
|
||||
}
|
||||
|
||||
void
|
||||
_cogl_disable_clip_planes (void)
|
||||
{
|
||||
@ -945,6 +817,7 @@ _cogl_features_init ()
|
||||
CoglFeatureFlags flags = 0;
|
||||
const gchar *gl_extensions;
|
||||
GLint max_clip_planes = 0;
|
||||
GLint num_stencil_bits = 0;
|
||||
|
||||
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
|
||||
|
||||
@ -1214,9 +1087,9 @@ _cogl_features_init ()
|
||||
flags |= COGL_FEATURE_OFFSCREEN_MULTISAMPLE;
|
||||
}
|
||||
|
||||
ctx->num_stencil_bits = 0;
|
||||
GE( glGetIntegerv (GL_STENCIL_BITS, &ctx->num_stencil_bits) );
|
||||
if (ctx->num_stencil_bits > 0)
|
||||
GE( glGetIntegerv (GL_STENCIL_BITS, &num_stencil_bits) );
|
||||
/* We need at least three stencil bits to combine clips */
|
||||
if (num_stencil_bits > 2)
|
||||
flags |= COGL_FEATURE_STENCIL_BUFFER;
|
||||
|
||||
GE( glGetIntegerv (GL_MAX_CLIP_PLANES, &max_clip_planes) );
|
||||
|
@ -55,9 +55,8 @@ cogl_create_context ()
|
||||
_context->enable_flags = 0;
|
||||
_context->color_alpha = 255;
|
||||
|
||||
_context->path_nodes = NULL;
|
||||
_context->path_nodes_cap = 0;
|
||||
_context->path_nodes_size = 0;
|
||||
_context->path_nodes = g_array_new (FALSE, FALSE, sizeof (CoglPathNode));
|
||||
_context->last_path = 0;
|
||||
|
||||
_context->texture_handles = NULL;
|
||||
_context->texture_vertices_size = 0;
|
||||
@ -84,6 +83,8 @@ cogl_create_context ()
|
||||
GE( glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) );
|
||||
cogl_enable (0);
|
||||
|
||||
_cogl_clip_stack_state_init ();
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@ -93,6 +94,11 @@ cogl_destroy_context ()
|
||||
if (_context == NULL)
|
||||
return;
|
||||
|
||||
_cogl_clip_stack_state_destroy ();
|
||||
|
||||
if (_context->path_nodes)
|
||||
g_array_free (_context->path_nodes, TRUE);
|
||||
|
||||
#ifdef HAVE_COGL_GLES2
|
||||
cogl_gles2_wrapper_deinit (&_context->gles2);
|
||||
#endif
|
||||
|
@ -27,6 +27,7 @@
|
||||
#define __COGL_CONTEXT_H
|
||||
|
||||
#include "cogl-primitives.h"
|
||||
#include "cogl-clip-stack.h"
|
||||
|
||||
#include "cogl-gles2-wrapper.h"
|
||||
|
||||
@ -42,7 +43,6 @@ typedef struct
|
||||
/* Features cache */
|
||||
CoglFeatureFlags feature_flags;
|
||||
gboolean features_cached;
|
||||
GLint num_stencil_bits;
|
||||
|
||||
/* Enable cache */
|
||||
gulong enable_flags;
|
||||
@ -55,9 +55,8 @@ typedef struct
|
||||
/* Primitives */
|
||||
CoglFixedVec2 path_start;
|
||||
CoglFixedVec2 path_pen;
|
||||
CoglFixedVec2 *path_nodes;
|
||||
guint path_nodes_cap;
|
||||
guint path_nodes_size;
|
||||
GArray *path_nodes;
|
||||
guint last_path;
|
||||
CoglFixedVec2 path_nodes_min;
|
||||
CoglFixedVec2 path_nodes_max;
|
||||
|
||||
@ -80,6 +79,9 @@ typedef struct
|
||||
/* Mesh */
|
||||
GArray *mesh_handles;
|
||||
|
||||
/* Clip stack */
|
||||
CoglClipStackState clip;
|
||||
|
||||
#ifdef HAVE_COGL_GLES2
|
||||
CoglGles2Wrapper gles2;
|
||||
|
||||
|
@ -87,45 +87,27 @@ _cogl_rectanglex (CoglFixed x,
|
||||
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
_cogl_path_clear_nodes ()
|
||||
{
|
||||
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
|
||||
|
||||
if (ctx->path_nodes)
|
||||
g_free(ctx->path_nodes);
|
||||
|
||||
ctx->path_nodes = (CoglFixedVec2*) g_malloc (2 * sizeof(CoglFixedVec2));
|
||||
ctx->path_nodes_size = 0;
|
||||
ctx->path_nodes_cap = 2;
|
||||
}
|
||||
|
||||
void
|
||||
_cogl_path_add_node (CoglFixed x,
|
||||
_cogl_path_add_node (gboolean new_sub_path,
|
||||
CoglFixed x,
|
||||
CoglFixed y)
|
||||
{
|
||||
CoglFixedVec2 *new_nodes = NULL;
|
||||
CoglPathNode new_node;
|
||||
|
||||
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
|
||||
|
||||
if (ctx->path_nodes_size == ctx->path_nodes_cap)
|
||||
{
|
||||
new_nodes = g_realloc (ctx->path_nodes,
|
||||
2 * ctx->path_nodes_cap
|
||||
* sizeof (CoglFixedVec2));
|
||||
new_node.x = x;
|
||||
new_node.y = y;
|
||||
new_node.path_size = 0;
|
||||
|
||||
if (new_nodes == NULL) return;
|
||||
if (new_sub_path || ctx->path_nodes->len == 0)
|
||||
ctx->last_path = ctx->path_nodes->len;
|
||||
|
||||
ctx->path_nodes = new_nodes;
|
||||
ctx->path_nodes_cap *= 2;
|
||||
}
|
||||
g_array_append_val (ctx->path_nodes, new_node);
|
||||
|
||||
ctx->path_nodes [ctx->path_nodes_size].x = x;
|
||||
ctx->path_nodes [ctx->path_nodes_size].y = y;
|
||||
ctx->path_nodes_size++;
|
||||
g_array_index (ctx->path_nodes, CoglPathNode, ctx->last_path).path_size++;
|
||||
|
||||
if (ctx->path_nodes_size == 1)
|
||||
if (ctx->path_nodes->len == 1)
|
||||
{
|
||||
ctx->path_nodes_min.x = ctx->path_nodes_max.x = x;
|
||||
ctx->path_nodes_min.y = ctx->path_nodes_max.y = y;
|
||||
@ -142,14 +124,42 @@ _cogl_path_add_node (CoglFixed x,
|
||||
void
|
||||
_cogl_path_stroke_nodes ()
|
||||
{
|
||||
guint path_start = 0;
|
||||
|
||||
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
|
||||
|
||||
cogl_enable (COGL_ENABLE_VERTEX_ARRAY
|
||||
| (ctx->color_alpha < 255
|
||||
? COGL_ENABLE_BLEND : 0));
|
||||
|
||||
GE( cogl_wrap_glVertexPointer (2, GL_FIXED, 0, ctx->path_nodes) );
|
||||
GE( cogl_wrap_glDrawArrays (GL_LINE_STRIP, 0, ctx->path_nodes_size) );
|
||||
while (path_start < ctx->path_nodes->len)
|
||||
{
|
||||
CoglPathNode *path = &g_array_index (ctx->path_nodes, CoglPathNode,
|
||||
path_start);
|
||||
|
||||
GE( cogl_wrap_glVertexPointer (2, GL_FIXED, sizeof (CoglPathNode),
|
||||
(guchar *) path
|
||||
+ G_STRUCT_OFFSET (CoglPathNode, x)) );
|
||||
GE( cogl_wrap_glDrawArrays (GL_LINE_STRIP, 0, path->path_size) );
|
||||
|
||||
path_start += path->path_size;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
_cogl_path_get_bounds (CoglFixedVec2 nodes_min,
|
||||
CoglFixedVec2 nodes_max,
|
||||
gint *bounds_x,
|
||||
gint *bounds_y,
|
||||
guint *bounds_w,
|
||||
guint *bounds_h)
|
||||
{
|
||||
*bounds_x = COGL_FIXED_FLOOR (nodes_min.x);
|
||||
*bounds_y = COGL_FIXED_FLOOR (nodes_min.y);
|
||||
*bounds_w = COGL_FIXED_CEIL (nodes_max.x
|
||||
- COGL_FIXED_FROM_INT (*bounds_x));
|
||||
*bounds_h = COGL_FIXED_CEIL (nodes_max.y
|
||||
- COGL_FIXED_FROM_INT (*bounds_y));
|
||||
}
|
||||
|
||||
static gint compare_ints (gconstpointer a,
|
||||
@ -158,209 +168,314 @@ static gint compare_ints (gconstpointer a,
|
||||
return GPOINTER_TO_INT(a)-GPOINTER_TO_INT(b);
|
||||
}
|
||||
|
||||
void
|
||||
_cogl_add_path_to_stencil_buffer (CoglFixedVec2 nodes_min,
|
||||
CoglFixedVec2 nodes_max,
|
||||
guint path_size,
|
||||
CoglPathNode *path,
|
||||
gboolean merge)
|
||||
{
|
||||
guint path_start = 0;
|
||||
guint sub_path_num = 0;
|
||||
gint bounds_x;
|
||||
gint bounds_y;
|
||||
guint bounds_w;
|
||||
guint bounds_h;
|
||||
|
||||
_cogl_path_get_bounds (nodes_min, nodes_max,
|
||||
&bounds_x, &bounds_y, &bounds_w, &bounds_h);
|
||||
|
||||
if (merge)
|
||||
{
|
||||
GE( glStencilMask (2) );
|
||||
GE( glStencilFunc (GL_LEQUAL, 0x2, 0x6) );
|
||||
}
|
||||
else
|
||||
{
|
||||
GE( glClear (GL_STENCIL_BUFFER_BIT) );
|
||||
GE( glStencilMask (1) );
|
||||
GE( glStencilFunc (GL_LEQUAL, 0x1, 0x3) );
|
||||
}
|
||||
|
||||
GE( cogl_wrap_glEnable (GL_STENCIL_TEST) );
|
||||
GE( glStencilOp (GL_INVERT, GL_INVERT, GL_INVERT) );
|
||||
|
||||
GE( glColorMask (FALSE, FALSE, FALSE, FALSE) );
|
||||
GE( glDepthMask (FALSE) );
|
||||
|
||||
while (path_start < path_size)
|
||||
{
|
||||
cogl_enable (COGL_ENABLE_VERTEX_ARRAY);
|
||||
|
||||
GE( cogl_wrap_glVertexPointer (2, GL_FIXED, sizeof (CoglPathNode),
|
||||
(guchar *) path
|
||||
+ G_STRUCT_OFFSET (CoglPathNode, x)) );
|
||||
GE( cogl_wrap_glDrawArrays (GL_TRIANGLE_FAN, 0, path->path_size) );
|
||||
|
||||
if (sub_path_num > 0)
|
||||
{
|
||||
/* Union the two stencil buffers bits into the least
|
||||
significant bit */
|
||||
GE( glStencilMask (merge ? 6 : 3) );
|
||||
GE( glStencilOp (GL_ZERO, GL_REPLACE, GL_REPLACE) );
|
||||
cogl_rectangle (bounds_x, bounds_y, bounds_w, bounds_h);
|
||||
|
||||
GE( glStencilOp (GL_INVERT, GL_INVERT, GL_INVERT) );
|
||||
}
|
||||
|
||||
GE( glStencilMask (merge ? 4 : 2) );
|
||||
|
||||
path_start += path->path_size;
|
||||
path += path->path_size;
|
||||
sub_path_num++;
|
||||
}
|
||||
|
||||
if (merge)
|
||||
{
|
||||
/* Now we have the new stencil buffer in bit 1 and the old
|
||||
stencil buffer in bit 0 so we need to intersect them */
|
||||
GE( glStencilMask (3) );
|
||||
GE( glStencilFunc (GL_NEVER, 0x2, 0x3) );
|
||||
GE( glStencilOp (GL_DECR, GL_DECR, GL_DECR) );
|
||||
/* Decrement all of the bits twice so that only pixels where the
|
||||
value is 3 will remain */
|
||||
GE( cogl_wrap_glPushMatrix () );
|
||||
GE( cogl_wrap_glLoadIdentity () );
|
||||
GE( cogl_wrap_glMatrixMode (GL_PROJECTION) );
|
||||
GE( cogl_wrap_glPushMatrix () );
|
||||
GE( cogl_wrap_glLoadIdentity () );
|
||||
cogl_rectanglex (-COGL_FIXED_1, -COGL_FIXED_1,
|
||||
COGL_FIXED_FROM_INT (2),
|
||||
COGL_FIXED_FROM_INT (2));
|
||||
cogl_rectanglex (-COGL_FIXED_1, -COGL_FIXED_1,
|
||||
COGL_FIXED_FROM_INT (2),
|
||||
COGL_FIXED_FROM_INT (2));
|
||||
GE( cogl_wrap_glPopMatrix () );
|
||||
GE( cogl_wrap_glMatrixMode (GL_MODELVIEW) );
|
||||
GE( cogl_wrap_glPopMatrix () );
|
||||
}
|
||||
|
||||
GE( glStencilMask (~(GLuint) 0) );
|
||||
GE( glDepthMask (TRUE) );
|
||||
GE( glColorMask (TRUE, TRUE, TRUE, TRUE) );
|
||||
|
||||
GE( glStencilFunc (GL_EQUAL, 0x1, 0x1) );
|
||||
GE( glStencilOp (GL_KEEP, GL_KEEP, GL_KEEP) );
|
||||
}
|
||||
|
||||
static void
|
||||
_cogl_path_fill_nodes_scanlines (CoglPathNode *path,
|
||||
guint path_size,
|
||||
gint bounds_x,
|
||||
gint bounds_y,
|
||||
guint bounds_w,
|
||||
guint bounds_h)
|
||||
{
|
||||
/* This is our edge list it stores intersections between our
|
||||
* curve and scanlines, it should probably be implemented with a
|
||||
* data structure that has smaller overhead for inserting the
|
||||
* curve/scanline intersections.
|
||||
*/
|
||||
GSList *scanlines[bounds_h];
|
||||
|
||||
gint i;
|
||||
gint prev_x;
|
||||
gint prev_y;
|
||||
gint first_x;
|
||||
gint first_y;
|
||||
gint lastdir=-2; /* last direction we vere moving */
|
||||
gint lastline=-1; /* the previous scanline we added to */
|
||||
|
||||
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
|
||||
|
||||
/* clear scanline intersection lists */
|
||||
for (i=0; i < bounds_h; i++)
|
||||
scanlines[i]=NULL;
|
||||
|
||||
first_x = prev_x = COGL_FIXED_TO_INT (path->x);
|
||||
first_y = prev_y = COGL_FIXED_TO_INT (path->y);
|
||||
|
||||
/* create scanline intersection list */
|
||||
for (i=1; i < path_size; i++)
|
||||
{
|
||||
gint dest_x = COGL_FIXED_TO_INT (path[i].x);
|
||||
gint dest_y = COGL_FIXED_TO_INT (path[i].y);
|
||||
gint ydir;
|
||||
gint dx;
|
||||
gint dy;
|
||||
gint y;
|
||||
|
||||
fill_close:
|
||||
dx = dest_x - prev_x;
|
||||
dy = dest_y - prev_y;
|
||||
|
||||
if (dy < 0)
|
||||
ydir = -1;
|
||||
else if (dy > 0)
|
||||
ydir = 1;
|
||||
else
|
||||
ydir = 0;
|
||||
|
||||
/* do linear interpolation between vertexes */
|
||||
for (y=prev_y; y!= dest_y; y += ydir)
|
||||
{
|
||||
|
||||
/* only add a point if the scanline has changed and we're
|
||||
* within bounds.
|
||||
*/
|
||||
if (y-bounds_y >= 0 &&
|
||||
y-bounds_y < bounds_h &&
|
||||
lastline != y)
|
||||
{
|
||||
gint x = prev_x + (dx * (y-prev_y)) / dy;
|
||||
|
||||
scanlines[ y - bounds_y ]=
|
||||
g_slist_insert_sorted (scanlines[ y - bounds_y],
|
||||
GINT_TO_POINTER(x),
|
||||
compare_ints);
|
||||
|
||||
if (ydir != lastdir && /* add a double entry when changing */
|
||||
lastdir!=-2) /* vertical direction */
|
||||
scanlines[ y - bounds_y ]=
|
||||
g_slist_insert_sorted (scanlines[ y - bounds_y],
|
||||
GINT_TO_POINTER(x),
|
||||
compare_ints);
|
||||
lastdir = ydir;
|
||||
lastline = y;
|
||||
}
|
||||
}
|
||||
|
||||
prev_x = dest_x;
|
||||
prev_y = dest_y;
|
||||
|
||||
/* if we're on the last knot, fake the first vertex being a
|
||||
next one */
|
||||
if (path_size == i+1)
|
||||
{
|
||||
dest_x = first_x;
|
||||
dest_y = first_y;
|
||||
i++; /* to make the loop finally end */
|
||||
goto fill_close;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
gint spans = 0;
|
||||
gint span_no;
|
||||
GLfixed *coords;
|
||||
|
||||
/* count number of spans */
|
||||
for (i=0; i < bounds_h; i++)
|
||||
{
|
||||
GSList *iter = scanlines[i];
|
||||
while (iter)
|
||||
{
|
||||
GSList *next = iter->next;
|
||||
if (!next)
|
||||
{
|
||||
break;
|
||||
}
|
||||
/* draw the segments that should be visible */
|
||||
spans ++;
|
||||
iter = next->next;
|
||||
}
|
||||
}
|
||||
coords = g_malloc0 (spans * sizeof (GLfixed) * 3 * 2 * 2);
|
||||
|
||||
span_no = 0;
|
||||
/* build list of triangles */
|
||||
for (i=0; i < bounds_h; i++)
|
||||
{
|
||||
GSList *iter = scanlines[i];
|
||||
while (iter)
|
||||
{
|
||||
GSList *next = iter->next;
|
||||
GLfixed x0, x1;
|
||||
GLfixed y0, y1;
|
||||
if (!next)
|
||||
break;
|
||||
|
||||
x0 = COGL_FIXED_FROM_INT (GPOINTER_TO_INT (iter->data));
|
||||
x1 = COGL_FIXED_FROM_INT (GPOINTER_TO_INT (next->data));
|
||||
y0 = COGL_FIXED_FROM_INT (bounds_y + i);
|
||||
y1 = COGL_FIXED_FROM_INT (bounds_y + i + 1) + 2048;
|
||||
/* render scanlines 1.0625 high to avoid gaps when
|
||||
transformed */
|
||||
|
||||
coords[span_no * 12 + 0] = x0;
|
||||
coords[span_no * 12 + 1] = y0;
|
||||
coords[span_no * 12 + 2] = x1;
|
||||
coords[span_no * 12 + 3] = y0;
|
||||
coords[span_no * 12 + 4] = x1;
|
||||
coords[span_no * 12 + 5] = y1;
|
||||
coords[span_no * 12 + 6] = x0;
|
||||
coords[span_no * 12 + 7] = y0;
|
||||
coords[span_no * 12 + 8] = x0;
|
||||
coords[span_no * 12 + 9] = y1;
|
||||
coords[span_no * 12 + 10] = x1;
|
||||
coords[span_no * 12 + 11] = y1;
|
||||
span_no ++;
|
||||
iter = next->next;
|
||||
}
|
||||
}
|
||||
for (i=0; i < bounds_h; i++)
|
||||
{
|
||||
g_slist_free (scanlines[i]);
|
||||
}
|
||||
|
||||
/* render triangles */
|
||||
cogl_enable (COGL_ENABLE_VERTEX_ARRAY
|
||||
| (ctx->color_alpha < 255 ? COGL_ENABLE_BLEND : 0));
|
||||
GE ( cogl_wrap_glVertexPointer (2, GL_FIXED, 0, coords ) );
|
||||
GE ( cogl_wrap_glDrawArrays (GL_TRIANGLES, 0, spans * 2 * 3));
|
||||
g_free (coords);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
_cogl_path_fill_nodes ()
|
||||
{
|
||||
guint bounds_x;
|
||||
guint bounds_y;
|
||||
gint bounds_x;
|
||||
gint bounds_y;
|
||||
guint bounds_w;
|
||||
guint bounds_h;
|
||||
|
||||
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
|
||||
|
||||
bounds_x = COGL_FIXED_FLOOR (ctx->path_nodes_min.x);
|
||||
bounds_y = COGL_FIXED_FLOOR (ctx->path_nodes_min.y);
|
||||
bounds_w = COGL_FIXED_CEIL (ctx->path_nodes_max.x - ctx->path_nodes_min.x);
|
||||
bounds_h = COGL_FIXED_CEIL (ctx->path_nodes_max.y - ctx->path_nodes_min.y);
|
||||
_cogl_path_get_bounds (ctx->path_nodes_min, ctx->path_nodes_max,
|
||||
&bounds_x, &bounds_y, &bounds_w, &bounds_h);
|
||||
|
||||
if (cogl_features_available (COGL_FEATURE_STENCIL_BUFFER))
|
||||
{
|
||||
GE( glClear (GL_STENCIL_BUFFER_BIT) );
|
||||
|
||||
GE( cogl_wrap_glEnable (GL_STENCIL_TEST) );
|
||||
GE( glStencilFunc (GL_NEVER, 0x0, 0x1) );
|
||||
GE( glStencilOp (GL_INVERT, GL_INVERT, GL_INVERT) );
|
||||
|
||||
GE( glStencilMask (1) );
|
||||
|
||||
cogl_enable (COGL_ENABLE_VERTEX_ARRAY
|
||||
| (ctx->color_alpha < 255 ? COGL_ENABLE_BLEND : 0));
|
||||
|
||||
GE( cogl_wrap_glVertexPointer (2, GL_FIXED, 0, ctx->path_nodes) );
|
||||
GE( cogl_wrap_glDrawArrays (GL_TRIANGLE_FAN, 0, ctx->path_nodes_size) );
|
||||
|
||||
GE( glStencilMask (~(GLuint) 0) );
|
||||
|
||||
/* Merge the stencil buffer with any clipping rectangles */
|
||||
_cogl_clip_stack_merge ();
|
||||
|
||||
GE( glStencilFunc (GL_EQUAL, 0x1, 0x1) );
|
||||
GE( glStencilOp (GL_KEEP, GL_KEEP, GL_KEEP) );
|
||||
_cogl_add_path_to_stencil_buffer (ctx->path_nodes_min,
|
||||
ctx->path_nodes_max,
|
||||
ctx->path_nodes->len,
|
||||
&g_array_index (ctx->path_nodes,
|
||||
CoglPathNode, 0),
|
||||
ctx->clip.stencil_used);
|
||||
|
||||
cogl_rectangle (bounds_x, bounds_y, bounds_w, bounds_h);
|
||||
|
||||
/* Rebuild the stencil clip */
|
||||
_cogl_clip_stack_rebuild (TRUE);
|
||||
/* The stencil buffer now contains garbage so the clip area needs to
|
||||
be rebuilt */
|
||||
ctx->clip.stack_dirty = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* This is our edge list it stores intersections between our
|
||||
* curve and scanlines, it should probably be implemented with a
|
||||
* data structure that has smaller overhead for inserting the
|
||||
* curve/scanline intersections.
|
||||
*/
|
||||
GSList *scanlines[bounds_h];
|
||||
guint path_start = 0;
|
||||
|
||||
gint i;
|
||||
gint prev_x;
|
||||
gint prev_y;
|
||||
gint first_x;
|
||||
gint first_y;
|
||||
gint lastdir=-2; /* last direction we vere moving */
|
||||
gint lastline=-1; /* the previous scanline we added to */
|
||||
while (path_start < ctx->path_nodes->len)
|
||||
{
|
||||
CoglPathNode *path = &g_array_index (ctx->path_nodes, CoglPathNode,
|
||||
path_start);
|
||||
|
||||
/* clear scanline intersection lists */
|
||||
for (i=0; i < bounds_h; i++)
|
||||
scanlines[i]=NULL;
|
||||
_cogl_path_fill_nodes_scanlines (path,
|
||||
path->path_size,
|
||||
bounds_x, bounds_y,
|
||||
bounds_w, bounds_h);
|
||||
|
||||
first_x = prev_x = COGL_FIXED_TO_INT (ctx->path_nodes[0].x);
|
||||
first_y = prev_y = COGL_FIXED_TO_INT (ctx->path_nodes[0].y);
|
||||
|
||||
/* create scanline intersection list */
|
||||
for (i=1; i<ctx->path_nodes_size; i++)
|
||||
{
|
||||
gint dest_x = COGL_FIXED_TO_INT (ctx->path_nodes[i].x);
|
||||
gint dest_y = COGL_FIXED_TO_INT (ctx->path_nodes[i].y);
|
||||
gint ydir;
|
||||
gint dx;
|
||||
gint dy;
|
||||
gint y;
|
||||
|
||||
fill_close:
|
||||
dx = dest_x - prev_x;
|
||||
dy = dest_y - prev_y;
|
||||
|
||||
if (dy < 0)
|
||||
ydir = -1;
|
||||
else if (dy > 0)
|
||||
ydir = 1;
|
||||
else
|
||||
ydir = 0;
|
||||
|
||||
/* do linear interpolation between vertexes */
|
||||
for (y=prev_y; y!= dest_y; y += ydir)
|
||||
{
|
||||
|
||||
/* only add a point if the scanline has changed and we're
|
||||
* within bounds.
|
||||
*/
|
||||
if (y-bounds_y >= 0 &&
|
||||
y-bounds_y < bounds_h &&
|
||||
lastline != y)
|
||||
{
|
||||
gint x = prev_x + (dx * (y-prev_y)) / dy;
|
||||
|
||||
scanlines[ y - bounds_y ]=
|
||||
g_slist_insert_sorted (scanlines[ y - bounds_y],
|
||||
GINT_TO_POINTER(x),
|
||||
compare_ints);
|
||||
|
||||
if (ydir != lastdir && /* add a double entry when changing */
|
||||
lastdir!=-2) /* vertical direction */
|
||||
scanlines[ y - bounds_y ]=
|
||||
g_slist_insert_sorted (scanlines[ y - bounds_y],
|
||||
GINT_TO_POINTER(x),
|
||||
compare_ints);
|
||||
lastdir = ydir;
|
||||
lastline = y;
|
||||
}
|
||||
}
|
||||
|
||||
prev_x = dest_x;
|
||||
prev_y = dest_y;
|
||||
|
||||
/* if we're on the last knot, fake the first vertex being a
|
||||
next one */
|
||||
if (ctx->path_nodes_size == i+1)
|
||||
{
|
||||
dest_x = first_x;
|
||||
dest_y = first_y;
|
||||
i++; /* to make the loop finally end */
|
||||
goto fill_close;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
gint spans = 0;
|
||||
gint span_no;
|
||||
GLfixed *coords;
|
||||
|
||||
/* count number of spans */
|
||||
for (i=0; i < bounds_h; i++)
|
||||
{
|
||||
GSList *iter = scanlines[i];
|
||||
while (iter)
|
||||
{
|
||||
GSList *next = iter->next;
|
||||
if (!next)
|
||||
{
|
||||
break;
|
||||
}
|
||||
/* draw the segments that should be visible */
|
||||
spans ++;
|
||||
iter = next->next;
|
||||
}
|
||||
}
|
||||
coords = g_malloc0 (spans * sizeof (GLfixed) * 3 * 2 * 2);
|
||||
|
||||
span_no = 0;
|
||||
/* build list of triangles */
|
||||
for (i=0; i < bounds_h; i++)
|
||||
{
|
||||
GSList *iter = scanlines[i];
|
||||
while (iter)
|
||||
{
|
||||
GSList *next = iter->next;
|
||||
GLfixed x0, x1;
|
||||
GLfixed y0, y1;
|
||||
if (!next)
|
||||
break;
|
||||
|
||||
x0 = COGL_FIXED_FROM_INT (GPOINTER_TO_INT (iter->data));
|
||||
x1 = COGL_FIXED_FROM_INT (GPOINTER_TO_INT (next->data));
|
||||
y0 = COGL_FIXED_FROM_INT (bounds_y + i);
|
||||
y1 = COGL_FIXED_FROM_INT (bounds_y + i + 1) + 2048;
|
||||
/* render scanlines 1.0625 high to avoid gaps when
|
||||
transformed */
|
||||
|
||||
coords[span_no * 12 + 0] = x0;
|
||||
coords[span_no * 12 + 1] = y0;
|
||||
coords[span_no * 12 + 2] = x1;
|
||||
coords[span_no * 12 + 3] = y0;
|
||||
coords[span_no * 12 + 4] = x1;
|
||||
coords[span_no * 12 + 5] = y1;
|
||||
coords[span_no * 12 + 6] = x0;
|
||||
coords[span_no * 12 + 7] = y0;
|
||||
coords[span_no * 12 + 8] = x0;
|
||||
coords[span_no * 12 + 9] = y1;
|
||||
coords[span_no * 12 + 10] = x1;
|
||||
coords[span_no * 12 + 11] = y1;
|
||||
span_no ++;
|
||||
iter = next->next;
|
||||
}
|
||||
}
|
||||
for (i=0; i < bounds_h; i++)
|
||||
{
|
||||
g_slist_free (scanlines[i]);
|
||||
}
|
||||
|
||||
/* render triangles */
|
||||
cogl_enable (COGL_ENABLE_VERTEX_ARRAY
|
||||
| (ctx->color_alpha < 255 ? COGL_ENABLE_BLEND : 0));
|
||||
GE ( cogl_wrap_glVertexPointer (2, GL_FIXED, 0, coords ) );
|
||||
GE ( cogl_wrap_glDrawArrays (GL_TRIANGLES, 0, spans * 2 * 3));
|
||||
g_free (coords);
|
||||
}
|
||||
path_start += path->path_size;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2325,6 +2325,8 @@ cogl_texture_rectangle (CoglHandle handle,
|
||||
if (!cogl_is_texture (handle))
|
||||
return;
|
||||
|
||||
cogl_clip_ensure ();
|
||||
|
||||
tex = _cogl_texture_pointer_from_handle (handle);
|
||||
|
||||
/* Make sure we got stuff to draw */
|
||||
@ -2379,6 +2381,8 @@ cogl_texture_polygon (CoglHandle handle,
|
||||
if (!cogl_is_texture (handle))
|
||||
return;
|
||||
|
||||
cogl_clip_ensure ();
|
||||
|
||||
tex = _cogl_texture_pointer_from_handle (handle);
|
||||
|
||||
/* GL ES has no GL_CLAMP_TO_BORDER wrap mode so the method used to
|
||||
|
154
gles/cogl.c
154
gles/cogl.c
@ -389,8 +389,6 @@ set_clip_plane (GLint plane_num,
|
||||
GE( cogl_wrap_glClipPlanex (plane_num, plane) );
|
||||
|
||||
GE( cogl_wrap_glPopMatrix () );
|
||||
|
||||
GE( cogl_wrap_glEnable (plane_num) );
|
||||
}
|
||||
|
||||
void
|
||||
@ -438,15 +436,6 @@ _cogl_set_clip_planes (CoglFixed x_offset,
|
||||
set_clip_plane (GL_CLIP_PLANE3, vertex_bl, vertex_tl);
|
||||
}
|
||||
|
||||
static int
|
||||
compare_y_coordinate (const void *a, const void *b)
|
||||
{
|
||||
GLfixed ay = ((const GLfixed *) a)[1];
|
||||
GLfixed by = ((const GLfixed *) b)[1];
|
||||
|
||||
return ay < by ? -1 : ay > by ? 1 : 0;
|
||||
}
|
||||
|
||||
void
|
||||
_cogl_add_stencil_clip (CoglFixed x_offset,
|
||||
CoglFixed y_offset,
|
||||
@ -454,19 +443,8 @@ _cogl_add_stencil_clip (CoglFixed x_offset,
|
||||
CoglFixed height,
|
||||
gboolean first)
|
||||
{
|
||||
gboolean has_clip_planes
|
||||
= cogl_features_available (COGL_FEATURE_FOUR_CLIP_PLANES);
|
||||
|
||||
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
|
||||
|
||||
if (has_clip_planes)
|
||||
{
|
||||
GE( cogl_wrap_glDisable (GL_CLIP_PLANE3) );
|
||||
GE( cogl_wrap_glDisable (GL_CLIP_PLANE2) );
|
||||
GE( cogl_wrap_glDisable (GL_CLIP_PLANE1) );
|
||||
GE( cogl_wrap_glDisable (GL_CLIP_PLANE0) );
|
||||
}
|
||||
|
||||
if (first)
|
||||
{
|
||||
GE( cogl_wrap_glEnable (GL_STENCIL_TEST) );
|
||||
@ -481,7 +459,7 @@ _cogl_add_stencil_clip (CoglFixed x_offset,
|
||||
|
||||
cogl_rectanglex (x_offset, y_offset, width, height);
|
||||
}
|
||||
else if (ctx->num_stencil_bits > 1)
|
||||
else
|
||||
{
|
||||
/* Add one to every pixel of the stencil buffer in the
|
||||
rectangle */
|
||||
@ -505,120 +483,6 @@ _cogl_add_stencil_clip (CoglFixed x_offset,
|
||||
GE( cogl_wrap_glMatrixMode (GL_MODELVIEW) );
|
||||
GE( cogl_wrap_glPopMatrix () );
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Slower fallback if there is exactly one stencil bit. This
|
||||
tries to draw enough triangles to tessalate around the
|
||||
rectangle so that it can subtract from the stencil buffer for
|
||||
every pixel in the screen except those in the rectangle */
|
||||
GLfixed modelview[16], projection[16];
|
||||
GLfixed temp_point[4];
|
||||
GLfixed left_edge, right_edge, bottom_edge, top_edge;
|
||||
int i;
|
||||
GLfixed points[16] =
|
||||
{
|
||||
x_offset, y_offset, 0, COGL_FIXED_1,
|
||||
x_offset + width, y_offset, 0, COGL_FIXED_1,
|
||||
x_offset, y_offset + height, 0, COGL_FIXED_1,
|
||||
x_offset + width, y_offset + height, 0, COGL_FIXED_1
|
||||
};
|
||||
GLfixed draw_points[12];
|
||||
|
||||
GE( cogl_wrap_glGetFixedv (GL_MODELVIEW_MATRIX, modelview) );
|
||||
GE( cogl_wrap_glGetFixedv (GL_PROJECTION_MATRIX, projection) );
|
||||
|
||||
/* Project all of the vertices into screen coordinates */
|
||||
for (i = 0; i < 4; i++)
|
||||
project_vertex (modelview, projection, points + i * 4);
|
||||
|
||||
/* Sort the points by y coordinate */
|
||||
qsort (points, 4, sizeof (GLfixed) * 4, compare_y_coordinate);
|
||||
|
||||
/* Put the bottom two pairs and the top two pairs in
|
||||
left-right order */
|
||||
if (points[0] > points[4])
|
||||
{
|
||||
memcpy (temp_point, points, sizeof (GLfixed) * 4);
|
||||
memcpy (points, points + 4, sizeof (GLfixed) * 4);
|
||||
memcpy (points + 4, temp_point, sizeof (GLfixed) * 4);
|
||||
}
|
||||
if (points[8] > points[12])
|
||||
{
|
||||
memcpy (temp_point, points + 8, sizeof (GLfixed) * 4);
|
||||
memcpy (points + 8, points + 12, sizeof (GLfixed) * 4);
|
||||
memcpy (points + 12, temp_point, sizeof (GLfixed) * 4);
|
||||
}
|
||||
|
||||
/* If the clip rect goes outside of the screen then use the
|
||||
extents of the rect instead */
|
||||
left_edge = MIN (-COGL_FIXED_1, MIN (points[0], points[8]));
|
||||
right_edge = MAX ( COGL_FIXED_1, MAX (points[4], points[12]));
|
||||
bottom_edge = MIN (-COGL_FIXED_1, MIN (points[1], points[5]));
|
||||
top_edge = MAX ( COGL_FIXED_1, MAX (points[9], points[13]));
|
||||
|
||||
/* Using the identity matrix for the projection and
|
||||
modelview matrix, draw the triangles around the inner
|
||||
rectangle */
|
||||
GE( glStencilFunc (GL_NEVER, 0x1, 0x1) );
|
||||
GE( glStencilOp (GL_ZERO, GL_ZERO, GL_ZERO) );
|
||||
GE( cogl_wrap_glPushMatrix () );
|
||||
GE( cogl_wrap_glLoadIdentity () );
|
||||
GE( cogl_wrap_glMatrixMode (GL_PROJECTION) );
|
||||
GE( cogl_wrap_glPushMatrix () );
|
||||
GE( cogl_wrap_glLoadIdentity () );
|
||||
|
||||
cogl_enable (COGL_ENABLE_VERTEX_ARRAY
|
||||
| (ctx->color_alpha < 255 ? COGL_ENABLE_BLEND : 0));
|
||||
GE( cogl_wrap_glVertexPointer (2, GL_FIXED, 0, draw_points) );
|
||||
|
||||
/* Clear the left side */
|
||||
draw_points[0] = left_edge; draw_points[1] = bottom_edge;
|
||||
draw_points[2] = points[0]; draw_points[3] = points[1];
|
||||
draw_points[4] = left_edge; draw_points[5] = points[1];
|
||||
draw_points[6] = points[8]; draw_points[7] = points[9];
|
||||
draw_points[8] = left_edge; draw_points[9] = points[9];
|
||||
draw_points[10] = left_edge; draw_points[11] = top_edge;
|
||||
GE( cogl_wrap_glDrawArrays (GL_TRIANGLE_STRIP, 0, 6) );
|
||||
|
||||
/* Clear the right side */
|
||||
draw_points[0] = right_edge; draw_points[1] = top_edge;
|
||||
draw_points[2] = points[12]; draw_points[3] = points[13];
|
||||
draw_points[4] = right_edge; draw_points[5] = points[13];
|
||||
draw_points[6] = points[4]; draw_points[7] = points[5];
|
||||
draw_points[8] = right_edge; draw_points[9] = points[5];
|
||||
draw_points[10] = right_edge; draw_points[11] = bottom_edge;
|
||||
GE( cogl_wrap_glDrawArrays (GL_TRIANGLE_STRIP, 0, 6) );
|
||||
|
||||
/* Clear the top side */
|
||||
draw_points[0] = left_edge; draw_points[1] = top_edge;
|
||||
draw_points[2] = points[8]; draw_points[3] = points[9];
|
||||
draw_points[4] = points[8]; draw_points[5] = top_edge;
|
||||
draw_points[6] = points[12]; draw_points[7] = points[13];
|
||||
draw_points[8] = points[12]; draw_points[9] = top_edge;
|
||||
draw_points[10] = right_edge; draw_points[11] = top_edge;
|
||||
GE( cogl_wrap_glDrawArrays (GL_TRIANGLE_STRIP, 0, 6) );
|
||||
|
||||
/* Clear the bottom side */
|
||||
draw_points[0] = left_edge; draw_points[1] = bottom_edge;
|
||||
draw_points[2] = points[0]; draw_points[3] = points[1];
|
||||
draw_points[4] = points[0]; draw_points[5] = bottom_edge;
|
||||
draw_points[6] = points[4]; draw_points[7] = points[5];
|
||||
draw_points[8] = points[4]; draw_points[9] = bottom_edge;
|
||||
draw_points[10] = right_edge; draw_points[11] = bottom_edge;
|
||||
GE( cogl_wrap_glDrawArrays (GL_TRIANGLE_STRIP, 0, 6) );
|
||||
|
||||
GE( cogl_wrap_glPopMatrix () );
|
||||
GE( cogl_wrap_glMatrixMode (GL_MODELVIEW) );
|
||||
GE( cogl_wrap_glPopMatrix () );
|
||||
}
|
||||
|
||||
if (has_clip_planes)
|
||||
{
|
||||
GE( cogl_wrap_glEnable (GL_CLIP_PLANE0) );
|
||||
GE( cogl_wrap_glEnable (GL_CLIP_PLANE1) );
|
||||
GE( cogl_wrap_glEnable (GL_CLIP_PLANE2) );
|
||||
GE( cogl_wrap_glEnable (GL_CLIP_PLANE3) );
|
||||
}
|
||||
|
||||
/* Restore the stencil mode */
|
||||
GE( glStencilFunc (GL_EQUAL, 0x1, 0x1) );
|
||||
@ -638,6 +502,15 @@ _cogl_disable_stencil_buffer (void)
|
||||
GE( cogl_wrap_glDisable (GL_STENCIL_TEST) );
|
||||
}
|
||||
|
||||
void
|
||||
_cogl_enable_clip_planes (void)
|
||||
{
|
||||
GE( cogl_wrap_glEnable (GL_CLIP_PLANE0) );
|
||||
GE( cogl_wrap_glEnable (GL_CLIP_PLANE1) );
|
||||
GE( cogl_wrap_glEnable (GL_CLIP_PLANE2) );
|
||||
GE( cogl_wrap_glEnable (GL_CLIP_PLANE3) );
|
||||
}
|
||||
|
||||
void
|
||||
_cogl_disable_clip_planes (void)
|
||||
{
|
||||
@ -818,12 +691,13 @@ _cogl_features_init ()
|
||||
{
|
||||
CoglFeatureFlags flags = 0;
|
||||
int max_clip_planes = 0;
|
||||
GLint num_stencil_bits = 0;
|
||||
|
||||
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
|
||||
|
||||
ctx->num_stencil_bits = 0;
|
||||
GE( cogl_wrap_glGetIntegerv (GL_STENCIL_BITS, &ctx->num_stencil_bits) );
|
||||
if (ctx->num_stencil_bits > 0)
|
||||
GE( cogl_wrap_glGetIntegerv (GL_STENCIL_BITS, &num_stencil_bits) );
|
||||
/* We need at least three stencil bits to combine clips */
|
||||
if (num_stencil_bits > 2)
|
||||
flags |= COGL_FEATURE_STENCIL_BUFFER;
|
||||
|
||||
GE( cogl_wrap_glGetIntegerv (GL_MAX_CLIP_PLANES, &max_clip_planes) );
|
||||
|
Loading…
Reference in New Issue
Block a user