summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cogl/cogl-clip-stack.c250
-rw-r--r--cogl/cogl-clip-stack.h29
-rw-r--r--cogl/cogl-clip-state.c26
-rw-r--r--cogl/cogl.h38
4 files changed, 280 insertions, 63 deletions
diff --git a/cogl/cogl-clip-stack.c b/cogl/cogl-clip-stack.c
index c01a74c0..c0786e0e 100644
--- a/cogl/cogl-clip-stack.c
+++ b/cogl/cogl-clip-stack.c
@@ -274,13 +274,19 @@ add_stencil_clip_rectangle (CoglFramebuffer *framebuffer,
cogl_pop_source ();
}
-void
-add_stencil_clip_path (CoglFramebuffer *framebuffer,
- CoglPath *path,
- gboolean merge,
- gboolean need_clear)
+typedef void (*SilhouettePaintCallback) (void *user_data);
+
+static void
+add_stencil_clip_silhouette (CoglFramebuffer *framebuffer,
+ SilhouettePaintCallback silhouette_callback,
+ float bounds_x1,
+ float bounds_y1,
+ float bounds_x2,
+ float bounds_y2,
+ gboolean merge,
+ gboolean need_clear,
+ void *user_data)
{
- CoglPathData *data = path->data;
CoglMatrixStack *modelview_stack =
_cogl_framebuffer_get_modelview_stack (framebuffer);
CoglMatrixStack *projection_stack =
@@ -330,10 +336,8 @@ add_stencil_clip_path (CoglFramebuffer *framebuffer,
/* Just clear the bounding box */
GE( ctx, glStencilMask (~(GLuint) 0) );
GE( ctx, glStencilOp (GL_ZERO, GL_ZERO, GL_ZERO) );
- _cogl_rectangle_immediate (data->path_nodes_min.x,
- data->path_nodes_min.y,
- data->path_nodes_max.x,
- data->path_nodes_max.y);
+ _cogl_rectangle_immediate (bounds_x1, bounds_y1,
+ bounds_x2, bounds_y2);
}
GE (ctx, glStencilMask (1));
GE (ctx, glStencilFunc (GL_LEQUAL, 0x1, 0x3));
@@ -341,8 +345,7 @@ add_stencil_clip_path (CoglFramebuffer *framebuffer,
GE (ctx, glStencilOp (GL_INVERT, GL_INVERT, GL_INVERT));
- if (path->data->path_nodes->len >= 3)
- _cogl_path_fill_nodes (path);
+ silhouette_callback (user_data);
if (merge)
{
@@ -383,6 +386,59 @@ add_stencil_clip_path (CoglFramebuffer *framebuffer,
}
static void
+paint_path_solhouette (void *user_data)
+{
+ CoglPath *path = user_data;
+ if (path->data->path_nodes->len >= 3)
+ _cogl_path_fill_nodes (path);
+}
+
+void
+add_stencil_clip_path (CoglFramebuffer *framebuffer,
+ CoglPath *path,
+ gboolean merge,
+ gboolean need_clear)
+{
+ CoglPathData *data = path->data;
+ add_stencil_clip_silhouette (framebuffer,
+ paint_path_solhouette,
+ data->path_nodes_min.x,
+ data->path_nodes_min.y,
+ data->path_nodes_max.x,
+ data->path_nodes_max.y,
+ merge,
+ need_clear,
+ path);
+}
+
+static void
+paint_primitive_solhouette (void *user_data)
+{
+ cogl_primitive_draw (user_data);
+}
+
+void
+add_stencil_clip_primitive (CoglFramebuffer *framebuffer,
+ CoglPrimitive *primitive,
+ float bounds_x1,
+ float bounds_y1,
+ float bounds_x2,
+ float bounds_y2,
+ gboolean merge,
+ gboolean need_clear)
+{
+ add_stencil_clip_silhouette (framebuffer,
+ paint_primitive_solhouette,
+ bounds_x1,
+ bounds_y1,
+ bounds_x2,
+ bounds_y2,
+ merge,
+ need_clear,
+ primitive);
+}
+
+static void
disable_stencil_buffer (void)
{
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
@@ -602,6 +658,39 @@ _cogl_clip_stack_push_from_path (CoglClipStack *stack,
}
CoglClipStack *
+_cogl_clip_stack_push_primitive (CoglClipStack *stack,
+ CoglPrimitive *primitive,
+ float bounds_x1,
+ float bounds_y1,
+ float bounds_x2,
+ float bounds_y2,
+ const CoglMatrix *modelview_matrix)
+{
+ CoglClipStackPrimitive *entry;
+
+ entry = _cogl_clip_stack_push_entry (stack,
+ sizeof (CoglClipStackPrimitive),
+ COGL_CLIP_STACK_PRIMITIVE);
+
+ entry->primitive = cogl_object_ref (primitive);
+
+ entry->matrix = *modelview_matrix;
+
+ entry->bounds_x1 = bounds_x1;
+ entry->bounds_y1 = bounds_y1;
+ entry->bounds_x2 = bounds_x2;
+ entry->bounds_y2 = bounds_y2;
+
+ /* NB: this is referring to the bounds in window coordinates as opposed
+ * to the bounds above in primitive local coordinates. */
+ _cogl_clip_stack_entry_set_bounds ((CoglClipStack *) entry,
+ bounds_x1, bounds_y1, bounds_x2, bounds_y2,
+ modelview_matrix);
+
+ return (CoglClipStack *) entry;
+}
+
+CoglClipStack *
_cogl_clip_stack_ref (CoglClipStack *entry)
{
/* A NULL pointer is considered a valid stack so we should accept
@@ -636,6 +725,11 @@ _cogl_clip_stack_unref (CoglClipStack *entry)
g_slice_free1 (sizeof (CoglClipStackPath), entry);
break;
+ case COGL_CLIP_STACK_PRIMITIVE:
+ cogl_object_unref (((CoglClipStackPrimitive *) entry)->primitive);
+ g_slice_free1 (sizeof (CoglClipStackPrimitive), entry);
+ break;
+
default:
g_assert_not_reached ();
}
@@ -789,69 +883,101 @@ _cogl_clip_stack_flush (CoglClipStack *stack,
order */
for (entry = stack; entry; entry = entry->parent)
{
- if (entry->type == COGL_CLIP_STACK_PATH)
+ switch (entry->type)
{
- CoglClipStackPath *path_entry = (CoglClipStackPath *) entry;
-
- COGL_NOTE (CLIPPING, "Adding stencil clip for path");
+ case COGL_CLIP_STACK_PATH:
+ {
+ CoglClipStackPath *path_entry = (CoglClipStackPath *) entry;
- _cogl_matrix_stack_push (modelview_stack);
- _cogl_matrix_stack_set (modelview_stack, &path_entry->matrix);
+ COGL_NOTE (CLIPPING, "Adding stencil clip for path");
- add_stencil_clip_path (framebuffer,
- path_entry->path,
- using_stencil_buffer,
- TRUE);
+ _cogl_matrix_stack_push (modelview_stack);
+ _cogl_matrix_stack_set (modelview_stack, &path_entry->matrix);
- _cogl_matrix_stack_pop (modelview_stack);
+ add_stencil_clip_path (framebuffer,
+ path_entry->path,
+ using_stencil_buffer,
+ TRUE);
- using_stencil_buffer = TRUE;
- }
- else if (entry->type == COGL_CLIP_STACK_RECT)
- {
- CoglClipStackRect *rect = (CoglClipStackRect *) entry;
+ _cogl_matrix_stack_pop (modelview_stack);
- /* We don't need to do anything extra if the clip for this
- rectangle was entirely described by its scissor bounds */
- if (!rect->can_be_scissor)
+ using_stencil_buffer = TRUE;
+ break;
+ }
+ case COGL_CLIP_STACK_PRIMITIVE:
{
+ CoglClipStackPrimitive *primitive_entry =
+ (CoglClipStackPrimitive *) entry;
+
+ COGL_NOTE (CLIPPING, "Adding stencil clip for primitive");
+
_cogl_matrix_stack_push (modelview_stack);
- _cogl_matrix_stack_set (modelview_stack, &rect->matrix);
+ _cogl_matrix_stack_set (modelview_stack, &primitive_entry->matrix);
- /* If we support clip planes and we haven't already used
- them then use that instead */
- if (has_clip_planes)
- {
- COGL_NOTE (CLIPPING, "Adding clip planes clip for rectangle");
-
- set_clip_planes (framebuffer,
- rect->x0,
- rect->y0,
- rect->x1,
- rect->y1);
- using_clip_planes = TRUE;
- /* We can't use clip planes a second time */
- has_clip_planes = FALSE;
- }
- else
- {
- COGL_NOTE (CLIPPING, "Adding stencil clip for rectangle");
-
- add_stencil_clip_rectangle (framebuffer,
- rect->x0,
- rect->y0,
- rect->x1,
- rect->y1,
- !using_stencil_buffer);
- using_stencil_buffer = TRUE;
- }
+ add_stencil_clip_primitive (framebuffer,
+ primitive_entry->primitive,
+ primitive_entry->bounds_x1,
+ primitive_entry->bounds_y1,
+ primitive_entry->bounds_x2,
+ primitive_entry->bounds_y2,
+ using_stencil_buffer,
+ TRUE);
_cogl_matrix_stack_pop (modelview_stack);
+
+ using_stencil_buffer = TRUE;
+ break;
}
+ case COGL_CLIP_STACK_RECT:
+ {
+ CoglClipStackRect *rect = (CoglClipStackRect *) entry;
+
+ /* We don't need to do anything extra if the clip for this
+ rectangle was entirely described by its scissor bounds */
+ if (!rect->can_be_scissor)
+ {
+ _cogl_matrix_stack_push (modelview_stack);
+ _cogl_matrix_stack_set (modelview_stack, &rect->matrix);
+
+ /* If we support clip planes and we haven't already used
+ them then use that instead */
+ if (has_clip_planes)
+ {
+ COGL_NOTE (CLIPPING,
+ "Adding clip planes clip for rectangle");
+
+ set_clip_planes (framebuffer,
+ rect->x0,
+ rect->y0,
+ rect->x1,
+ rect->y1);
+ using_clip_planes = TRUE;
+ /* We can't use clip planes a second time */
+ has_clip_planes = FALSE;
+ }
+ else
+ {
+ COGL_NOTE (CLIPPING, "Adding stencil clip for rectangle");
+
+ add_stencil_clip_rectangle (framebuffer,
+ rect->x0,
+ rect->y0,
+ rect->x1,
+ rect->y1,
+ !using_stencil_buffer);
+ using_stencil_buffer = TRUE;
+ }
+
+ _cogl_matrix_stack_pop (modelview_stack);
+ }
+ break;
+ }
+ case COGL_CLIP_STACK_WINDOW_RECT:
+ break;
+ /* We don't need to do anything for window space rectangles because
+ * their functionality is entirely implemented by the entry bounding
+ * box */
}
- /* We don't need to do anything for window space rectangles
- because their functionality is entirely implemented by the
- entry bounding box */
}
/* Enabling clip planes is delayed to now so that they won't affect
diff --git a/cogl/cogl-clip-stack.h b/cogl/cogl-clip-stack.h
index 6188f511..0a77a183 100644
--- a/cogl/cogl-clip-stack.h
+++ b/cogl/cogl-clip-stack.h
@@ -40,12 +40,14 @@ typedef struct _CoglClipStack CoglClipStack;
typedef struct _CoglClipStackRect CoglClipStackRect;
typedef struct _CoglClipStackWindowRect CoglClipStackWindowRect;
typedef struct _CoglClipStackPath CoglClipStackPath;
+typedef struct _CoglClipStackPrimitive CoglClipStackPrimitive;
typedef enum
{
COGL_CLIP_STACK_RECT,
COGL_CLIP_STACK_WINDOW_RECT,
- COGL_CLIP_STACK_PATH
+ COGL_CLIP_STACK_PATH,
+ COGL_CLIP_STACK_PRIMITIVE
} CoglClipStackType;
/* A clip stack consists a list of entries. Each entry has a reference
@@ -149,6 +151,21 @@ struct _CoglClipStackPath
CoglPath *path;
};
+struct _CoglClipStackPrimitive
+{
+ CoglClipStack _parent_data;
+
+ /* The matrix that was current when the clip was set */
+ CoglMatrix matrix;
+
+ CoglPrimitive *primitive;
+
+ float bounds_x1;
+ float bounds_y1;
+ float bounds_x2;
+ float bounds_y2;
+};
+
CoglClipStack *
_cogl_clip_stack_push_window_rectangle (CoglClipStack *stack,
int x_offset,
@@ -168,6 +185,16 @@ CoglClipStack *
_cogl_clip_stack_push_from_path (CoglClipStack *stack,
CoglPath *path,
const CoglMatrix *modelview_matrix);
+
+CoglClipStack *
+_cogl_clip_stack_push_primitive (CoglClipStack *stack,
+ CoglPrimitive *primitive,
+ float bounds_x1,
+ float bounds_y1,
+ float bounds_x2,
+ float bounds_y2,
+ const CoglMatrix *modelview_matrix);
+
CoglClipStack *
_cogl_clip_stack_pop (CoglClipStack *stack);
diff --git a/cogl/cogl-clip-state.c b/cogl/cogl-clip-state.c
index 8ef3f4bd..1f234718 100644
--- a/cogl/cogl-clip-state.c
+++ b/cogl/cogl-clip-state.c
@@ -125,6 +125,32 @@ cogl_clip_push_from_path (void)
ctx->current_path = cogl2_path_new ();
}
+void
+cogl_clip_push_primitive (CoglPrimitive *primitive,
+ float bounds_x1,
+ float bounds_y1,
+ float bounds_x2,
+ float bounds_y2)
+{
+ CoglFramebuffer *framebuffer;
+ CoglClipState *clip_state;
+ CoglMatrix modelview_matrix;
+
+ _COGL_GET_CONTEXT (ctx, NO_RETVAL);
+
+ framebuffer = cogl_get_draw_framebuffer ();
+ clip_state = _cogl_framebuffer_get_clip_state (framebuffer);
+
+ cogl_get_modelview_matrix (&modelview_matrix);
+
+ clip_state->stacks->data =
+ _cogl_clip_stack_push_primitive (clip_state->stacks->data,
+ primitive,
+ bounds_x1, bounds_y1,
+ bounds_x2, bounds_y2,
+ &modelview_matrix);
+}
+
static void
_cogl_clip_pop_real (CoglClipState *clip_state)
{
diff --git a/cogl/cogl.h b/cogl/cogl.h
index 240fa2a9..4cebfa20 100644
--- a/cogl/cogl.h
+++ b/cogl/cogl.h
@@ -844,6 +844,44 @@ cogl_clip_push_rectangle (float x0,
void
cogl_clip_push_from_path_preserve (void);
+#ifdef COGL_ENABLE_EXPERIMENTAL_2_0_API
+#define cogl_clip_push_primitive cogl_clip_push_primitive_EXP
+/**
+ * cogl_clip_push_primitive:
+ * @primitive: A #CoglPrimitive describing a flat 2D shape
+ * @bounds_x1: x coordinate for the top-left corner of the primitives
+ * bounds
+ * @bounds_y1: y coordinate for the top-left corner of the primitives
+ * bounds
+ * @bounds_x2: x coordinate for the top-left corner of the primitives
+ * bounds
+ * @bounds_y2: x coordinate for the bottom-right corner of the
+ * primitives bounds.
+ * @bounds_x1: y coordinate for the bottom-right corner of the
+ * primitives bounds.
+ *
+ * Sets a new clipping area using a 2D shaped described with a
+ * #CoglPrimitive. The shape must not contain self overlapping
+ * geometry and must lie on a single 2D plane. A bounding box of the
+ * 2D shape in local coordinates (the same coordinates used to
+ * describe the shape) must be given. It is acceptable for the bounds
+ * to be larger than the true bounds but behaviour is undefined if the
+ * bounds are smaller than the true bounds.
+ *
+ * The clipping area is intersected with the previous clipping area.
+ * To restore the previous clipping area, call cogl_clip_pop().
+ *
+ * Since: 1.10
+ * Stability: unstable
+ */
+void
+cogl_clip_push_primitive (CoglPrimitive *primitive,
+ float bounds_x1,
+ float bounds_y1,
+ float bounds_x2,
+ float bounds_y2);
+#endif
+
/**
* cogl_clip_pop:
*