mirror of
https://github.com/brl/mutter.git
synced 2024-11-26 18:11:05 -05:00
Bug 1172 - Disjoint paths and clip to path
* clutter/cogl/cogl-path.h: * clutter/cogl/common/cogl-primitives.c: * clutter/cogl/common/cogl-primitives.h: * clutter/cogl/gl/cogl-primitives.c: * clutter/cogl/gles/cogl-primitives.c: Changed the semantics of cogl_path_move_to. Previously this always started a new path but now it instead starts a new disjoint sub path. The path isn't cleared until you call either cogl_path_stroke, cogl_path_fill or cogl_path_new. There are also cogl_path_stroke_preserve and cogl_path_fill_preserve functions. * clutter/cogl/gl/cogl-context.c: * clutter/cogl/gl/cogl-context.h: * clutter/cogl/gles/cogl-context.c: * clutter/cogl/gles/cogl-context.h: Convert the path nodes array to a GArray. * clutter/cogl/gl/cogl-texture.c: * clutter/cogl/gles/cogl-texture.c: Call cogl_clip_ensure * clutter/cogl/common/cogl-clip-stack.c: * clutter/cogl/common/cogl-clip-stack.h: Simplified the clip stack code quite a bit to make it more maintainable. Previously whenever you added a new clip it would go through a separate route to immediately intersect with the current clip and when you removed it again it would immediately rebuild the entire clip. Now when you add or remove a clip it doesn't do anything immediately but just sets a dirty flag instead. * clutter/cogl/gl/cogl.c: * clutter/cogl/gles/cogl.c: Taken away the code to intersect stencil clips when there is exactly one stencil bit. It won't work with path clips and I don't know of any platform that doesn't have eight or zero stencil bits. It needs at least three bits to intersect a path with an existing clip. cogl_features_init now just decides you don't have a stencil buffer at all if you have less than three bits. * clutter/cogl/cogl.h.in: New functions and documentation. * tests/interactive/test-clip.c: Replaced with a different test that lets you add and remove clips. The three different mouse buttons add clips in different shapes. This makes it easier to test multiple levels of clipping. * tests/interactive/test-cogl-primitives.c: Use cogl_path_stroke_preserve when using the same path again. * doc/reference/cogl/cogl-sections.txt: Document the new functions.
This commit is contained in:
parent
bb2272992b
commit
89e7552ca3
55
ChangeLog
55
ChangeLog
@ -1,3 +1,58 @@
|
||||
2008-12-04 Neil Roberts <neil@linux.intel.com>
|
||||
|
||||
Bug 1172 - Disjoint paths and clip to path
|
||||
|
||||
* clutter/cogl/cogl-path.h:
|
||||
* clutter/cogl/common/cogl-primitives.c:
|
||||
* clutter/cogl/common/cogl-primitives.h:
|
||||
* clutter/cogl/gl/cogl-primitives.c:
|
||||
* clutter/cogl/gles/cogl-primitives.c: Changed the semantics of
|
||||
cogl_path_move_to. Previously this always started a new path but
|
||||
now it instead starts a new disjoint sub path. The path isn't
|
||||
cleared until you call either cogl_path_stroke, cogl_path_fill or
|
||||
cogl_path_new. There are also cogl_path_stroke_preserve and
|
||||
cogl_path_fill_preserve functions.
|
||||
|
||||
* clutter/cogl/gl/cogl-context.c:
|
||||
* clutter/cogl/gl/cogl-context.h:
|
||||
* clutter/cogl/gles/cogl-context.c:
|
||||
* clutter/cogl/gles/cogl-context.h: Convert the path nodes array
|
||||
to a GArray.
|
||||
|
||||
* clutter/cogl/gl/cogl-texture.c:
|
||||
* clutter/cogl/gles/cogl-texture.c: Call cogl_clip_ensure
|
||||
|
||||
* clutter/cogl/common/cogl-clip-stack.c:
|
||||
* clutter/cogl/common/cogl-clip-stack.h: Simplified the clip
|
||||
stack code quite a bit to make it more maintainable. Previously
|
||||
whenever you added a new clip it would go through a separate route
|
||||
to immediately intersect with the current clip and when you
|
||||
removed it again it would immediately rebuild the entire clip. Now
|
||||
when you add or remove a clip it doesn't do anything immediately
|
||||
but just sets a dirty flag instead.
|
||||
|
||||
* clutter/cogl/gl/cogl.c:
|
||||
* clutter/cogl/gles/cogl.c: Taken away the code to intersect
|
||||
stencil clips when there is exactly one stencil bit. It won't work
|
||||
with path clips and I don't know of any platform that doesn't have
|
||||
eight or zero stencil bits. It needs at least three bits to
|
||||
intersect a path with an existing clip. cogl_features_init now
|
||||
just decides you don't have a stencil buffer at all if you have
|
||||
less than three bits.
|
||||
|
||||
* clutter/cogl/cogl.h.in: New functions and documentation.
|
||||
|
||||
* tests/interactive/test-clip.c: Replaced with a different test
|
||||
that lets you add and remove clips. The three different mouse
|
||||
buttons add clips in different shapes. This makes it easier to
|
||||
test multiple levels of clipping.
|
||||
|
||||
* tests/interactive/test-cogl-primitives.c: Use
|
||||
cogl_path_stroke_preserve when using the same path again.
|
||||
|
||||
* doc/reference/cogl/cogl-sections.txt: Document the new
|
||||
functions.
|
||||
|
||||
2008-12-03 Robert Bragg <robert@linux.intel.com>
|
||||
|
||||
Bug 1303 - clutter_glx_texture_pixmap_using_extension doesn't check if
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
||||
cogl_clip_ensure ();
|
||||
|
||||
if (ctx->path_nodes_size == 0)
|
||||
return;
|
||||
|
||||
_cogl_path_fill_nodes();
|
||||
if (ctx->path_nodes->len == 0)
|
||||
return;
|
||||
|
||||
_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
|
||||
{
|
||||
|
@ -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_size = 0;
|
||||
@ -122,6 +121,9 @@ cogl_create_context ()
|
||||
GE( glColorMask (TRUE, TRUE, TRUE, FALSE) );
|
||||
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;
|
||||
|
||||
@ -76,6 +75,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));
|
||||
|
||||
if (new_nodes == NULL) return;
|
||||
|
||||
ctx->path_nodes = new_nodes;
|
||||
ctx->path_nodes_cap *= 2;
|
||||
}
|
||||
|
||||
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++;
|
||||
|
||||
if (ctx->path_nodes_size == 1)
|
||||
new_node.x = COGL_FIXED_TO_FLOAT (x);
|
||||
new_node.y = COGL_FIXED_TO_FLOAT (y);
|
||||
new_node.path_size = 0;
|
||||
|
||||
if (new_sub_path || ctx->path_nodes->len == 0)
|
||||
ctx->last_path = ctx->path_nodes->len;
|
||||
|
||||
g_array_append_val (ctx->path_nodes, new_node);
|
||||
|
||||
g_array_index (ctx->path_nodes, CoglPathNode, ctx->last_path).path_size++;
|
||||
|
||||
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));
|
||||
|
||||
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) );
|
||||
|
||||
GE( glVertexPointer (2, GL_FLOAT, 0, ctx->path_nodes) );
|
||||
GE( glDrawArrays (GL_LINE_STRIP, 0, ctx->path_nodes_size) );
|
||||
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) );
|
||||
|
||||
GE( glEnable (GL_STENCIL_TEST) );
|
||||
GE( glStencilFunc (GL_NEVER, 0x0, 0x1) );
|
||||
GE( glStencilOp (GL_INVERT, GL_INVERT, GL_INVERT) );
|
||||
_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( 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) );
|
||||
_cogl_path_get_bounds (ctx->path_nodes_min, ctx->path_nodes_max,
|
||||
&bounds_x, &bounds_y, &bounds_w, &bounds_h);
|
||||
|
||||
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_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;
|
||||
}
|
||||
|
@ -2197,6 +2197,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 */
|
||||
@ -2242,6 +2244,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
|
||||
|
@ -457,8 +457,6 @@ set_clip_plane (GLint plane_num,
|
||||
GE( glClipPlane (plane_num, plane) );
|
||||
|
||||
GE( glPopMatrix () );
|
||||
|
||||
GE( glEnable (plane_num) );
|
||||
}
|
||||
|
||||
void
|
||||
@ -513,15 +511,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 +518,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 +536,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 +561,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 +586,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 +811,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 +1081,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,10 +55,9 @@ 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;
|
||||
_context->texture_vertices = NULL;
|
||||
@ -83,6 +82,8 @@ cogl_create_context ()
|
||||
GE( glColorMask (TRUE, TRUE, TRUE, FALSE) );
|
||||
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;
|
||||
|
||||
_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));
|
||||
|
||||
if (new_nodes == NULL) return;
|
||||
CoglPathNode new_node;
|
||||
|
||||
ctx->path_nodes = new_nodes;
|
||||
ctx->path_nodes_cap *= 2;
|
||||
}
|
||||
|
||||
ctx->path_nodes [ctx->path_nodes_size].x = x;
|
||||
ctx->path_nodes [ctx->path_nodes_size].y = y;
|
||||
ctx->path_nodes_size++;
|
||||
|
||||
if (ctx->path_nodes_size == 1)
|
||||
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
|
||||
|
||||
new_node.x = x;
|
||||
new_node.y = y;
|
||||
new_node.path_size = 0;
|
||||
|
||||
if (new_sub_path || ctx->path_nodes->len == 0)
|
||||
ctx->last_path = ctx->path_nodes->len;
|
||||
|
||||
g_array_append_val (ctx->path_nodes, new_node);
|
||||
|
||||
g_array_index (ctx->path_nodes, CoglPathNode, ctx->last_path).path_size++;
|
||||
|
||||
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) );
|
||||
_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( 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_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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2324,6 +2324,8 @@ cogl_texture_rectangle (CoglHandle handle,
|
||||
/* Check if valid texture */
|
||||
if (!cogl_is_texture (handle))
|
||||
return;
|
||||
|
||||
cogl_clip_ensure ();
|
||||
|
||||
tex = _cogl_texture_pointer_from_handle (handle);
|
||||
|
||||
@ -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
|
||||
|
@ -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) );
|
||||
|
@ -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
|
||||
|
@ -1,128 +1,336 @@
|
||||
#include <clutter/clutter.h>
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <gmodule.h>
|
||||
|
||||
#define TL_SCALE 5.0f
|
||||
|
||||
typedef struct _CallbackData CallbackData;
|
||||
typedef struct _Clip Clip;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
CLIP_NONE,
|
||||
CLIP_RECTANGLE,
|
||||
CLIP_ELLIPSE,
|
||||
CLIP_SHAPES
|
||||
} ClipType;
|
||||
|
||||
struct _Clip
|
||||
{
|
||||
ClipType type;
|
||||
gint x1, y1, x2, y2;
|
||||
};
|
||||
|
||||
struct _CallbackData
|
||||
{
|
||||
ClutterActor *stage, *group, *rect, *hand;
|
||||
ClutterActor *stage;
|
||||
CoglHandle hand;
|
||||
|
||||
Clip current_clip;
|
||||
|
||||
GSList *clips;
|
||||
};
|
||||
|
||||
static const char
|
||||
instructions[] =
|
||||
"Press and drag any of the three mouse buttons to add a clip with different "
|
||||
"shapes. Press 'r' to reset or 'u' to undo the last clip.";
|
||||
|
||||
static void
|
||||
on_new_frame (ClutterTimeline *tl, int frame_num, CallbackData *data)
|
||||
path_shapes (gint x, gint y, gint width, gint height)
|
||||
{
|
||||
cogl_path_move_to (CLUTTER_INT_TO_FIXED (x), CLUTTER_INT_TO_FIXED (y));
|
||||
cogl_path_line_to (CLUTTER_INT_TO_FIXED (x),
|
||||
CLUTTER_INT_TO_FIXED (y + height * 4 / 5));
|
||||
cogl_path_line_to (CLUTTER_INT_TO_FIXED (x + width * 4 / 15),
|
||||
CLUTTER_INT_TO_FIXED (y + height * 4 / 5));
|
||||
cogl_path_close ();
|
||||
|
||||
cogl_path_rectangle (CLUTTER_INT_TO_FIXED (x + width / 3),
|
||||
CLUTTER_INT_TO_FIXED (y),
|
||||
CLUTTER_INT_TO_FIXED (width * 4 / 15),
|
||||
CLUTTER_INT_TO_FIXED (height * 4 / 5));
|
||||
|
||||
cogl_path_ellipse (CLUTTER_INT_TO_FIXED (x + width * 4 / 5),
|
||||
CLUTTER_INT_TO_FIXED (y + height * 2 / 5),
|
||||
CLUTTER_INT_TO_FIXED (width * 2 / 15),
|
||||
CLUTTER_INT_TO_FIXED (height * 2 / 5));
|
||||
}
|
||||
|
||||
static void
|
||||
draw_shapes (gint x, gint y)
|
||||
{
|
||||
path_shapes (x, y, 300, 100);
|
||||
cogl_set_source_color4ub (0x00, 0x00, 0xff, 0xff);
|
||||
cogl_path_fill_preserve ();
|
||||
cogl_set_source_color4ub (0xff, 0x00, 0x00, 0xff);
|
||||
cogl_path_stroke ();
|
||||
}
|
||||
|
||||
static void
|
||||
make_clip_path (Clip *clip)
|
||||
{
|
||||
switch (clip->type)
|
||||
{
|
||||
case CLIP_NONE:
|
||||
break;
|
||||
|
||||
case CLIP_RECTANGLE:
|
||||
cogl_path_rectangle (CLUTTER_INT_TO_FIXED (clip->x1),
|
||||
CLUTTER_INT_TO_FIXED (clip->y1),
|
||||
CLUTTER_INT_TO_FIXED (clip->x2 - clip->x1),
|
||||
CLUTTER_INT_TO_FIXED (clip->y2 - clip->y1));
|
||||
break;
|
||||
|
||||
case CLIP_ELLIPSE:
|
||||
cogl_path_ellipse (CLUTTER_INT_TO_FIXED (clip->x1 + clip->x2) / 2,
|
||||
CLUTTER_INT_TO_FIXED (clip->y1 + clip->y2) / 2,
|
||||
CLUTTER_INT_TO_FIXED (clip->x2 - clip->x1) / 2,
|
||||
CLUTTER_INT_TO_FIXED (clip->y2 - clip->y1) / 2);
|
||||
break;
|
||||
|
||||
case CLIP_SHAPES:
|
||||
{
|
||||
int x, y, width, height;
|
||||
|
||||
if (clip->x1 < clip->x2)
|
||||
{
|
||||
x = clip->x1;
|
||||
width = clip->x2 - x;
|
||||
}
|
||||
else
|
||||
{
|
||||
x = clip->x2;
|
||||
width = clip->x1 - x;
|
||||
}
|
||||
if (clip->y1 < clip->y2)
|
||||
{
|
||||
y = clip->y1;
|
||||
height = clip->y2 - y;
|
||||
}
|
||||
else
|
||||
{
|
||||
y = clip->y2;
|
||||
height = clip->y1 - y;
|
||||
}
|
||||
|
||||
path_shapes (x, y, width, height);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
on_paint (ClutterActor *actor, CallbackData *data)
|
||||
{
|
||||
int i;
|
||||
int stage_width = clutter_actor_get_width (data->stage);
|
||||
int stage_height = clutter_actor_get_height (data->stage);
|
||||
gdouble progress = clutter_timeline_get_progress (tl);
|
||||
gdouble angle = progress * 2 * M_PI * TL_SCALE;
|
||||
gdouble rotation[3];
|
||||
ClutterGeometry stage_size;
|
||||
guint hand_width, hand_height;
|
||||
GSList *node;
|
||||
|
||||
gdouble xpos = stage_width * 0.45 * sin (angle) + stage_width / 8;
|
||||
gdouble ypos = stage_height * 0.45 * sin (angle) + stage_height / 8;
|
||||
gdouble zpos = stage_width * cos (angle) - stage_width / 2;
|
||||
clutter_actor_get_allocation_geometry (data->stage, &stage_size);
|
||||
|
||||
clutter_actor_set_position (data->hand, xpos, ypos);
|
||||
clutter_actor_set_depth (data->hand, zpos);
|
||||
clutter_actor_set_rotation (data->hand, CLUTTER_Y_AXIS,
|
||||
angle / M_PI * 180.0 * 3,
|
||||
clutter_actor_get_width (data->hand) / 2,
|
||||
clutter_actor_get_height (data->hand) / 2,
|
||||
0);
|
||||
hand_width = cogl_texture_get_width (data->hand);
|
||||
hand_height = cogl_texture_get_height (data->hand);
|
||||
|
||||
memset (rotation, 0, sizeof (rotation));
|
||||
|
||||
if (progress < 1 / 3.0)
|
||||
rotation[2] = 360 * progress * 3;
|
||||
else if (progress < 2 / 3.0)
|
||||
rotation[1] = 360 * progress * 3;
|
||||
else
|
||||
rotation[0] = 360 * progress * 3;
|
||||
|
||||
for (i = 0; i < 3; i++)
|
||||
/* Setup the clipping */
|
||||
for (node = data->clips; node; node = node->next)
|
||||
{
|
||||
clutter_actor_set_rotation (data->group, i,
|
||||
rotation[i],
|
||||
clutter_actor_get_width (data->rect) / 2,
|
||||
clutter_actor_get_height (data->rect) / 2,
|
||||
0);
|
||||
clutter_actor_set_rotation (data->rect, i,
|
||||
rotation[i],
|
||||
clutter_actor_get_width (data->rect) / 2,
|
||||
clutter_actor_get_height (data->rect) / 2,
|
||||
0);
|
||||
Clip *clip = (Clip *) node->data;
|
||||
|
||||
if (clip->type == CLIP_RECTANGLE)
|
||||
cogl_clip_set (CLUTTER_INT_TO_FIXED (clip->x1),
|
||||
CLUTTER_INT_TO_FIXED (clip->y1),
|
||||
CLUTTER_INT_TO_FIXED (clip->x2 - clip->x1),
|
||||
CLUTTER_INT_TO_FIXED (clip->y2 - clip->y1));
|
||||
else
|
||||
{
|
||||
make_clip_path (clip);
|
||||
cogl_clip_set_from_path ();
|
||||
}
|
||||
}
|
||||
|
||||
/* Draw a rectangle filling the entire stage */
|
||||
cogl_set_source_color4ub (0x80, 0x80, 0xff, 0xff);
|
||||
cogl_rectangle (0, 0, stage_size.width, stage_size.height);
|
||||
|
||||
draw_shapes (10, 10);
|
||||
|
||||
/* Draw the hand at different rotations */
|
||||
for (i = -2; i <= 2; i++)
|
||||
{
|
||||
cogl_push_matrix ();
|
||||
|
||||
cogl_translate (stage_size.width / 2 + stage_size.width / 6 * i,
|
||||
stage_size.height / 2, 0);
|
||||
|
||||
cogl_rotate (i * 40, 0, 1, 0);
|
||||
|
||||
cogl_set_source_color4ub (0xff, 0xff, 0xff, 0xff);
|
||||
|
||||
cogl_texture_rectangle (data->hand,
|
||||
CLUTTER_INT_TO_FIXED (-hand_width / 2),
|
||||
CLUTTER_INT_TO_FIXED (-hand_height / 2),
|
||||
CLUTTER_INT_TO_FIXED (hand_width / 2),
|
||||
CLUTTER_INT_TO_FIXED (hand_height / 2),
|
||||
0, 0, CFX_ONE, CFX_ONE);
|
||||
|
||||
cogl_pop_matrix ();
|
||||
}
|
||||
|
||||
draw_shapes (stage_size.width - 310, stage_size.height - 110);
|
||||
|
||||
/* Remove all of the clipping */
|
||||
g_slist_foreach (data->clips, (GFunc) cogl_clip_unset, NULL);
|
||||
|
||||
/* Draw the bounding box for each of the clips */
|
||||
for (node = data->clips; node; node = node->next)
|
||||
{
|
||||
Clip *clip = (Clip *) node->data;
|
||||
|
||||
make_clip_path (clip);
|
||||
cogl_set_source_color4ub (0x00, 0x00, 0xff, 0xff);
|
||||
cogl_path_stroke ();
|
||||
}
|
||||
|
||||
/* Draw the bounding box for the pending new clip */
|
||||
if (data->current_clip.type != CLIP_NONE)
|
||||
{
|
||||
make_clip_path (&data->current_clip);
|
||||
cogl_set_source_color4ub (0xff, 0x00, 0x00, 0xff);
|
||||
cogl_path_stroke ();
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
on_button_press (ClutterActor *stage, ClutterButtonEvent *event,
|
||||
CallbackData *data)
|
||||
{
|
||||
data->current_clip.x1 = data->current_clip.x2 = event->x;
|
||||
data->current_clip.y1 = data->current_clip.y2 = event->y;
|
||||
|
||||
data->current_clip.type
|
||||
= event->button == 1 ? CLIP_RECTANGLE
|
||||
: event->button == 2 ? CLIP_SHAPES
|
||||
: CLIP_ELLIPSE;
|
||||
|
||||
clutter_actor_queue_redraw (stage);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
on_button_release (ClutterActor *stage, ClutterButtonEvent *event,
|
||||
CallbackData *data)
|
||||
{
|
||||
if (data->current_clip.type != CLIP_NONE)
|
||||
{
|
||||
data->clips = g_slist_prepend (data->clips,
|
||||
g_slice_copy (sizeof (Clip),
|
||||
&data->current_clip));
|
||||
|
||||
data->current_clip.type = CLIP_NONE;
|
||||
}
|
||||
|
||||
clutter_actor_queue_redraw (stage);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
on_motion (ClutterActor *stage, ClutterMotionEvent *event,
|
||||
CallbackData *data)
|
||||
{
|
||||
if (data->current_clip.type != CLIP_NONE)
|
||||
{
|
||||
data->current_clip.x2 = event->x;
|
||||
data->current_clip.y2 = event->y;
|
||||
|
||||
clutter_actor_queue_redraw (stage);
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
free_clips (CallbackData *data)
|
||||
{
|
||||
GSList *node;
|
||||
|
||||
for (node = data->clips; node; node = node->next)
|
||||
g_slice_free (Clip, node->data);
|
||||
|
||||
g_slist_free (data->clips);
|
||||
|
||||
data->clips = NULL;
|
||||
}
|
||||
|
||||
static gpointer
|
||||
on_key_press (ClutterActor *stage, ClutterKeyEvent *event,
|
||||
CallbackData *data)
|
||||
{
|
||||
switch (event->keyval)
|
||||
{
|
||||
case CLUTTER_r:
|
||||
free_clips (data);
|
||||
clutter_actor_queue_redraw (stage);
|
||||
break;
|
||||
|
||||
case CLUTTER_u:
|
||||
if (data->clips)
|
||||
{
|
||||
g_slice_free (Clip, data->clips->data);
|
||||
data->clips = g_slist_delete_link (data->clips, data->clips);
|
||||
clutter_actor_queue_redraw (stage);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
G_MODULE_EXPORT int
|
||||
test_clip_main (int argc, char **argv)
|
||||
{
|
||||
ClutterGeometry geom;
|
||||
ClutterTimeline *tl;
|
||||
ClutterColor blue = { 0x40, 0x40, 0xff, 0xff };
|
||||
CallbackData data;
|
||||
ClutterActor *other_hand;
|
||||
int x, y;
|
||||
ClutterActor *stub_actor, *label;
|
||||
|
||||
clutter_init (&argc, &argv);
|
||||
|
||||
data.current_clip.type = CLIP_NONE;
|
||||
data.clips = NULL;
|
||||
|
||||
data.stage = clutter_stage_get_default ();
|
||||
|
||||
data.group = clutter_group_new ();
|
||||
stub_actor = clutter_rectangle_new ();
|
||||
clutter_container_add (CLUTTER_CONTAINER (data.stage), stub_actor, NULL);
|
||||
|
||||
clutter_actor_get_geometry (data.stage, &geom);
|
||||
geom.x = geom.width / 4;
|
||||
geom.y = geom.height / 4;
|
||||
geom.width /= 2;
|
||||
geom.height /= 2;
|
||||
clutter_actor_set_geometry (data.group, &geom);
|
||||
data.hand = cogl_texture_new_from_file ("redhand.png", 64, FALSE,
|
||||
COGL_PIXEL_FORMAT_ANY, NULL);
|
||||
|
||||
data.rect = clutter_rectangle_new_with_color (&blue);
|
||||
clutter_actor_set_geometry (data.rect, &geom);
|
||||
clutter_container_add (CLUTTER_CONTAINER (data.stage), data.rect, NULL);
|
||||
label = clutter_label_new_with_text ("Sans 12px", instructions);
|
||||
clutter_label_set_line_wrap (CLUTTER_LABEL (label), TRUE);
|
||||
clutter_actor_set_width (label, clutter_actor_get_width (data.stage) - 310);
|
||||
clutter_actor_set_y (label,
|
||||
clutter_actor_get_height (data.stage)
|
||||
- clutter_actor_get_height (label));
|
||||
clutter_container_add (CLUTTER_CONTAINER (data.stage), label, NULL);
|
||||
|
||||
clutter_container_add (CLUTTER_CONTAINER (data.stage), data.group, NULL);
|
||||
g_signal_connect (stub_actor, "paint", G_CALLBACK (on_paint), &data);
|
||||
|
||||
clutter_actor_set_clip (data.group, 0, 0, geom.width, geom.height);
|
||||
|
||||
data.hand = clutter_texture_new_from_file ("redhand.png", NULL);
|
||||
if (data.hand == NULL)
|
||||
{
|
||||
g_critical ("pixbuf loading failed");
|
||||
exit (1);
|
||||
}
|
||||
clutter_container_add (CLUTTER_CONTAINER (data.group), data.hand, NULL);
|
||||
|
||||
/* Add a hand at each of the four corners of the group */
|
||||
for (y = 0; y < 2; y++)
|
||||
for (x = 0; x < 2; x++)
|
||||
{
|
||||
other_hand = clutter_clone_texture_new (CLUTTER_TEXTURE (data.hand));
|
||||
clutter_actor_set_anchor_point_from_gravity
|
||||
(other_hand, CLUTTER_GRAVITY_CENTER);
|
||||
clutter_actor_set_position (other_hand,
|
||||
x * geom.width,
|
||||
y * geom.height);
|
||||
clutter_container_add (CLUTTER_CONTAINER (data.group),
|
||||
other_hand, NULL);
|
||||
}
|
||||
|
||||
clutter_actor_raise_top (data.hand);
|
||||
|
||||
tl = clutter_timeline_new (360 * TL_SCALE, 60);
|
||||
clutter_timeline_start (tl);
|
||||
clutter_timeline_set_loop (tl, TRUE);
|
||||
|
||||
g_signal_connect (tl, "new-frame", G_CALLBACK (on_new_frame), &data);
|
||||
g_signal_connect (data.stage, "button-press-event",
|
||||
G_CALLBACK (on_button_press), &data);
|
||||
g_signal_connect (data.stage, "button-release-event",
|
||||
G_CALLBACK (on_button_release), &data);
|
||||
g_signal_connect (data.stage, "motion-event",
|
||||
G_CALLBACK (on_motion), &data);
|
||||
g_signal_connect (data.stage, "key-press-event",
|
||||
G_CALLBACK (on_key_press), &data);
|
||||
|
||||
clutter_actor_show (data.stage);
|
||||
|
||||
clutter_main ();
|
||||
|
||||
cogl_texture_unref (data.hand);
|
||||
|
||||
free_clips (&data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -204,11 +204,11 @@ test_coglbox_paint(ClutterActor *self)
|
||||
cogl_push_matrix ();
|
||||
|
||||
paint_func[paint_index] ();
|
||||
|
||||
|
||||
cogl_translate (100, 100, 0);
|
||||
cogl_set_source_color4ub (0, 160, 0, 255);
|
||||
cogl_path_stroke ();
|
||||
|
||||
cogl_path_stroke_preserve ();
|
||||
|
||||
cogl_translate (150, 0, 0);
|
||||
cogl_set_source_color4ub (200, 0, 0, 255);
|
||||
cogl_path_fill ();
|
||||
|
Loading…
Reference in New Issue
Block a user