diff options
-rw-r--r-- | cogl/cogl-clip-stack.c | 250 | ||||
-rw-r--r-- | cogl/cogl-clip-stack.h | 29 | ||||
-rw-r--r-- | cogl/cogl-clip-state.c | 26 | ||||
-rw-r--r-- | cogl/cogl.h | 38 |
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: * |