summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobert Bragg <robert@linux.intel.com>2012-09-19 20:37:32 +0100
committerRobert Bragg <robert@linux.intel.com>2012-09-25 20:50:45 +0100
commitacf989f1bb628282c53d1249b2e3fc6f6579f1e9 (patch)
treee8d5d3031179ba08a81e91ba182fbf78691ad744
parent90587418233b6438290741d80aedf193ae660cad (diff)
downloadcogl-acf989f1bb628282c53d1249b2e3fc6f6579f1e9.tar.gz
clip-stack: Splits out opengl specific code
As part of an on-going effort to enable non-opengl drivers for Cogl this splits out the opengl specific code in cogl-clip-stack.c into cogl/driver/cogl-clip-stack-gl.c Reviewed-by: Neil Roberts <neil@linux.intel.com>
-rw-r--r--cogl/Makefile.am2
-rw-r--r--cogl/cogl-clip-stack.c604
-rw-r--r--cogl/cogl-driver.h7
-rw-r--r--cogl/driver/gl/cogl-clip-stack-gl-private.h39
-rw-r--r--cogl/driver/gl/cogl-clip-stack-gl.c633
-rw-r--r--cogl/driver/gl/gl/cogl-driver-gl.c2
-rw-r--r--cogl/driver/gl/gles/cogl-driver-gles.c2
7 files changed, 688 insertions, 601 deletions
diff --git a/cogl/Makefile.am b/cogl/Makefile.am
index 9387b0d8..7b078152 100644
--- a/cogl/Makefile.am
+++ b/cogl/Makefile.am
@@ -146,6 +146,8 @@ cogl_driver_sources += \
$(srcdir)/driver/gl/cogl-texture-2d-gl.c \
$(srcdir)/driver/gl/cogl-attribute-gl-private.h \
$(srcdir)/driver/gl/cogl-attribute-gl.c \
+ $(srcdir)/driver/gl/cogl-clip-stack-gl-private.h \
+ $(srcdir)/driver/gl/cogl-clip-stack-gl.c \
$(srcdir)/driver/gl/cogl-pipeline-opengl.c \
$(srcdir)/driver/gl/cogl-pipeline-opengl-private.h \
$(srcdir)/driver/gl/cogl-pipeline-fragend-glsl.c \
diff --git a/cogl/cogl-clip-stack.c b/cogl/cogl-clip-stack.c
index d8dbb3dc..aad74817 100644
--- a/cogl/cogl-clip-stack.c
+++ b/cogl/cogl-clip-stack.c
@@ -16,7 +16,8 @@
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ * License along with this library. If not, see
+ * <http://www.gnu.org/licenses/>.
*
*
*/
@@ -47,429 +48,7 @@
#include "cogl-offscreen.h"
#include "cogl-matrix-stack.h"
-#ifndef GL_CLIP_PLANE0
-#define GL_CLIP_PLANE0 0x3000
-#define GL_CLIP_PLANE1 0x3001
-#define GL_CLIP_PLANE2 0x3002
-#define GL_CLIP_PLANE3 0x3003
-#define GL_CLIP_PLANE4 0x3004
-#define GL_CLIP_PLANE5 0x3005
-#endif
-
-static void
-project_vertex (const CoglMatrix *modelview_projection,
- float *vertex)
-{
- int i;
-
- cogl_matrix_transform_point (modelview_projection,
- &vertex[0], &vertex[1],
- &vertex[2], &vertex[3]);
-
- /* Convert from homogenized coordinates */
- for (i = 0; i < 4; i++)
- vertex[i] /= vertex[3];
-}
-
-static void
-set_clip_plane (CoglFramebuffer *framebuffer,
- GLint plane_num,
- const float *vertex_a,
- const float *vertex_b)
-{
- GLfloat planef[4];
- double planed[4];
- GLfloat angle;
- CoglMatrixStack *modelview_stack =
- _cogl_framebuffer_get_modelview_stack (framebuffer);
- CoglMatrixStack *projection_stack =
- _cogl_framebuffer_get_projection_stack (framebuffer);
- CoglMatrix inverse_projection;
-
- _COGL_GET_CONTEXT (ctx, NO_RETVAL);
-
- _cogl_matrix_stack_get_inverse (projection_stack, &inverse_projection);
-
- /* Calculate the angle between the axes and the line crossing the
- two points */
- angle = atan2f (vertex_b[1] - vertex_a[1],
- vertex_b[0] - vertex_a[0]) * (180.0/G_PI);
-
- _cogl_matrix_stack_push (modelview_stack);
-
- /* Load the inverse of the projection matrix so we can specify the plane
- * in screen coordinates */
- _cogl_matrix_stack_set (modelview_stack, &inverse_projection);
-
- /* Rotate about point a */
- _cogl_matrix_stack_translate (modelview_stack,
- vertex_a[0], vertex_a[1], vertex_a[2]);
- /* Rotate the plane by the calculated angle so that it will connect
- the two points */
- _cogl_matrix_stack_rotate (modelview_stack, angle, 0.0f, 0.0f, 1.0f);
- _cogl_matrix_stack_translate (modelview_stack,
- -vertex_a[0], -vertex_a[1], -vertex_a[2]);
-
- /* Clip planes can only be used when a fixed function backend is in
- use so we know we can directly push this matrix to the builtin
- state */
- _cogl_matrix_entry_flush_to_gl_builtins (ctx,
- modelview_stack->last_entry,
- COGL_MATRIX_MODELVIEW,
- framebuffer,
- FALSE /* don't disable flip */);
-
- planef[0] = 0;
- planef[1] = -1.0;
- planef[2] = 0;
- planef[3] = vertex_a[1];
-
- switch (ctx->driver)
- {
- default:
- g_assert_not_reached ();
- break;
-
- case COGL_DRIVER_GLES1:
- GE( ctx, glClipPlanef (plane_num, planef) );
- break;
-
- case COGL_DRIVER_GL:
- planed[0] = planef[0];
- planed[1] = planef[1];
- planed[2] = planef[2];
- planed[3] = planef[3];
- GE( ctx, glClipPlane (plane_num, planed) );
- break;
- }
-
- _cogl_matrix_stack_pop (modelview_stack);
-}
-
-static void
-set_clip_planes (CoglFramebuffer *framebuffer,
- CoglMatrixEntry *modelview_entry,
- float x_1,
- float y_1,
- float x_2,
- float y_2)
-{
- CoglMatrix modelview_matrix;
- CoglMatrixStack *projection_stack =
- _cogl_framebuffer_get_projection_stack (framebuffer);
- CoglMatrix projection_matrix;
- CoglMatrix modelview_projection;
- float signed_area;
-
- float vertex_tl[4] = { x_1, y_1, 0, 1.0 };
- float vertex_tr[4] = { x_2, y_1, 0, 1.0 };
- float vertex_bl[4] = { x_1, y_2, 0, 1.0 };
- float vertex_br[4] = { x_2, y_2, 0, 1.0 };
-
- _cogl_matrix_stack_get (projection_stack, &projection_matrix);
- _cogl_matrix_entry_get (modelview_entry, &modelview_matrix);
-
- cogl_matrix_multiply (&modelview_projection,
- &projection_matrix,
- &modelview_matrix);
-
- project_vertex (&modelview_projection, vertex_tl);
- project_vertex (&modelview_projection, vertex_tr);
- project_vertex (&modelview_projection, vertex_bl);
- project_vertex (&modelview_projection, vertex_br);
-
- /* Calculate the signed area of the polygon formed by the four
- vertices so that we can know its orientation */
- signed_area = (vertex_tl[0] * (vertex_tr[1] - vertex_bl[1])
- + vertex_tr[0] * (vertex_br[1] - vertex_tl[1])
- + vertex_br[0] * (vertex_bl[1] - vertex_tr[1])
- + vertex_bl[0] * (vertex_tl[1] - vertex_br[1]));
-
- /* Set the clip planes to form lines between all of the vertices
- using the same orientation as we calculated */
- if (signed_area > 0.0f)
- {
- /* counter-clockwise */
- set_clip_plane (framebuffer, GL_CLIP_PLANE0, vertex_tl, vertex_bl);
- set_clip_plane (framebuffer, GL_CLIP_PLANE1, vertex_bl, vertex_br);
- set_clip_plane (framebuffer, GL_CLIP_PLANE2, vertex_br, vertex_tr);
- set_clip_plane (framebuffer, GL_CLIP_PLANE3, vertex_tr, vertex_tl);
- }
- else
- {
- /* clockwise */
- set_clip_plane (framebuffer, GL_CLIP_PLANE0, vertex_tl, vertex_tr);
- set_clip_plane (framebuffer, GL_CLIP_PLANE1, vertex_tr, vertex_br);
- set_clip_plane (framebuffer, GL_CLIP_PLANE2, vertex_br, vertex_bl);
- set_clip_plane (framebuffer, GL_CLIP_PLANE3, vertex_bl, vertex_tl);
- }
-}
-
-static void
-add_stencil_clip_rectangle (CoglFramebuffer *framebuffer,
- CoglMatrixEntry *modelview_entry,
- float x_1,
- float y_1,
- float x_2,
- float y_2,
- CoglBool first)
-{
- CoglMatrixStack *projection_stack =
- _cogl_framebuffer_get_projection_stack (framebuffer);
- CoglContext *ctx = cogl_framebuffer_get_context (framebuffer);
-
- /* NB: This can be called while flushing the journal so we need
- * to be very conservative with what state we change.
- */
-
- _cogl_context_set_current_projection_entry (ctx,
- projection_stack->last_entry);
- _cogl_context_set_current_modelview_entry (ctx, modelview_entry);
-
- if (first)
- {
- GE( ctx, glEnable (GL_STENCIL_TEST) );
-
- /* Initially disallow everything */
- GE( ctx, glClearStencil (0) );
- GE( ctx, glClear (GL_STENCIL_BUFFER_BIT) );
-
- /* Punch out a hole to allow the rectangle */
- GE( ctx, glStencilFunc (GL_NEVER, 0x1, 0x1) );
- GE( ctx, glStencilOp (GL_REPLACE, GL_REPLACE, GL_REPLACE) );
-
- _cogl_rectangle_immediate (framebuffer,
- ctx->stencil_pipeline,
- x_1, y_1, x_2, y_2);
- }
- else
- {
- /* Add one to every pixel of the stencil buffer in the
- rectangle */
- GE( ctx, glStencilFunc (GL_NEVER, 0x1, 0x3) );
- GE( ctx, glStencilOp (GL_INCR, GL_INCR, GL_INCR) );
- _cogl_rectangle_immediate (framebuffer,
- ctx->stencil_pipeline,
- x_1, y_1, x_2, y_2);
-
- /* Subtract one from all pixels in the stencil buffer so that
- only pixels where both the original stencil buffer and the
- rectangle are set will be valid */
- GE( ctx, glStencilOp (GL_DECR, GL_DECR, GL_DECR) );
-
- _cogl_context_set_current_projection_entry (ctx, &ctx->identity_entry);
- _cogl_context_set_current_modelview_entry (ctx, &ctx->identity_entry);
-
- _cogl_rectangle_immediate (framebuffer,
- ctx->stencil_pipeline,
- -1.0, -1.0, 1.0, 1.0);
- }
-
- /* Restore the stencil mode */
- GE( ctx, glStencilFunc (GL_EQUAL, 0x1, 0x1) );
- GE( ctx, glStencilOp (GL_KEEP, GL_KEEP, GL_KEEP) );
-}
-
-typedef void (*SilhouettePaintCallback) (CoglFramebuffer *framebuffer,
- CoglPipeline *pipeline,
- void *user_data);
-
-static void
-add_stencil_clip_silhouette (CoglFramebuffer *framebuffer,
- SilhouettePaintCallback silhouette_callback,
- CoglMatrixEntry *modelview_entry,
- float bounds_x1,
- float bounds_y1,
- float bounds_x2,
- float bounds_y2,
- CoglBool merge,
- CoglBool need_clear,
- void *user_data)
-{
- CoglMatrixStack *projection_stack =
- _cogl_framebuffer_get_projection_stack (framebuffer);
- CoglContext *ctx = cogl_framebuffer_get_context (framebuffer);
-
- /* NB: This can be called while flushing the journal so we need
- * to be very conservative with what state we change.
- */
-
- _cogl_context_set_current_projection_entry (ctx,
- projection_stack->last_entry);
- _cogl_context_set_current_modelview_entry (ctx, modelview_entry);
-
- _cogl_pipeline_flush_gl_state (ctx->stencil_pipeline, framebuffer, FALSE, 0);
-
- GE( ctx, glEnable (GL_STENCIL_TEST) );
-
- GE( ctx, glColorMask (FALSE, FALSE, FALSE, FALSE) );
- GE( ctx, glDepthMask (FALSE) );
-
- if (merge)
- {
- GE (ctx, glStencilMask (2));
- GE (ctx, glStencilFunc (GL_LEQUAL, 0x2, 0x6));
- }
- else
- {
- /* If we're not using the stencil buffer for clipping then we
- don't need to clear the whole stencil buffer, just the area
- that will be drawn */
- if (need_clear)
- /* If this is being called from the clip stack code then it
- will have set up a scissor for the minimum bounding box of
- all of the clips. That box will likely mean that this
- _cogl_clear won't need to clear the entire
- buffer. _cogl_framebuffer_clear_without_flush4f is used instead
- of cogl_clear because it won't try to flush the journal */
- _cogl_framebuffer_clear_without_flush4f (framebuffer,
- COGL_BUFFER_BIT_STENCIL,
- 0, 0, 0, 0);
- else
- {
- /* Just clear the bounding box */
- GE( ctx, glStencilMask (~(GLuint) 0) );
- GE( ctx, glStencilOp (GL_ZERO, GL_ZERO, GL_ZERO) );
- _cogl_rectangle_immediate (framebuffer,
- ctx->stencil_pipeline,
- bounds_x1, bounds_y1,
- bounds_x2, bounds_y2);
- }
- GE (ctx, glStencilMask (1));
- GE (ctx, glStencilFunc (GL_LEQUAL, 0x1, 0x3));
- }
-
- GE (ctx, glStencilOp (GL_INVERT, GL_INVERT, GL_INVERT));
-
- silhouette_callback (framebuffer, ctx->stencil_pipeline, user_data);
-
- 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 (ctx, glStencilMask (3));
- GE (ctx, glStencilFunc (GL_NEVER, 0x2, 0x3));
- GE (ctx, glStencilOp (GL_DECR, GL_DECR, GL_DECR));
- /* Decrement all of the bits twice so that only pixels where the
- value is 3 will remain */
-
- _cogl_context_set_current_projection_entry (ctx, &ctx->identity_entry);
- _cogl_context_set_current_modelview_entry (ctx, &ctx->identity_entry);
-
- _cogl_rectangle_immediate (framebuffer, ctx->stencil_pipeline,
- -1.0, -1.0, 1.0, 1.0);
- _cogl_rectangle_immediate (framebuffer, ctx->stencil_pipeline,
- -1.0, -1.0, 1.0, 1.0);
- }
- GE (ctx, glStencilMask (~(GLuint) 0));
- GE (ctx, glDepthMask (TRUE));
- GE (ctx, glColorMask (TRUE, TRUE, TRUE, TRUE));
-
- GE (ctx, glStencilFunc (GL_EQUAL, 0x1, 0x1));
- GE (ctx, glStencilOp (GL_KEEP, GL_KEEP, GL_KEEP));
-}
-
-static void
-paint_path_silhouette (CoglFramebuffer *framebuffer,
- CoglPipeline *pipeline,
- void *user_data)
-{
- CoglPath *path = user_data;
- if (path->data->path_nodes->len >= 3)
- _cogl_path_fill_nodes (path,
- framebuffer,
- pipeline,
- COGL_DRAW_SKIP_JOURNAL_FLUSH |
- COGL_DRAW_SKIP_PIPELINE_VALIDATION |
- COGL_DRAW_SKIP_FRAMEBUFFER_FLUSH);
-}
-
-static void
-add_stencil_clip_path (CoglFramebuffer *framebuffer,
- CoglMatrixEntry *modelview_entry,
- CoglPath *path,
- CoglBool merge,
- CoglBool need_clear)
-{
- CoglPathData *data = path->data;
- add_stencil_clip_silhouette (framebuffer,
- paint_path_silhouette,
- modelview_entry,
- 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_silhouette (CoglFramebuffer *framebuffer,
- CoglPipeline *pipeline,
- void *user_data)
-{
- _cogl_framebuffer_draw_primitive (framebuffer,
- pipeline,
- user_data,
- COGL_DRAW_SKIP_JOURNAL_FLUSH |
- COGL_DRAW_SKIP_PIPELINE_VALIDATION |
- COGL_DRAW_SKIP_FRAMEBUFFER_FLUSH);
-}
-
-static void
-add_stencil_clip_primitive (CoglFramebuffer *framebuffer,
- CoglMatrixEntry *modelview_entry,
- CoglPrimitive *primitive,
- float bounds_x1,
- float bounds_y1,
- float bounds_x2,
- float bounds_y2,
- CoglBool merge,
- CoglBool need_clear)
-{
- add_stencil_clip_silhouette (framebuffer,
- paint_primitive_silhouette,
- modelview_entry,
- bounds_x1,
- bounds_y1,
- bounds_x2,
- bounds_y2,
- merge,
- need_clear,
- primitive);
-}
-
-static void
-disable_stencil_buffer (void)
-{
- _COGL_GET_CONTEXT (ctx, NO_RETVAL);
-
- GE( ctx, glDisable (GL_STENCIL_TEST) );
-}
-
-static void
-enable_clip_planes (void)
-{
- _COGL_GET_CONTEXT (ctx, NO_RETVAL);
-
- GE( ctx, glEnable (GL_CLIP_PLANE0) );
- GE( ctx, glEnable (GL_CLIP_PLANE1) );
- GE( ctx, glEnable (GL_CLIP_PLANE2) );
- GE( ctx, glEnable (GL_CLIP_PLANE3) );
-}
-
-static void
-disable_clip_planes (void)
-{
- _COGL_GET_CONTEXT (ctx, NO_RETVAL);
-
- GE( ctx, glDisable (GL_CLIP_PLANE3) );
- GE( ctx, glDisable (GL_CLIP_PLANE2) );
- GE( ctx, glDisable (GL_CLIP_PLANE1) );
- GE( ctx, glDisable (GL_CLIP_PLANE0) );
-}
static void *
_cogl_clip_stack_push_entry (CoglClipStack *clip_stack,
@@ -879,183 +458,6 @@ _cogl_clip_stack_flush (CoglClipStack *stack,
CoglFramebuffer *framebuffer)
{
CoglContext *ctx = framebuffer->context;
- int has_clip_planes;
- CoglBool using_clip_planes = FALSE;
- CoglBool using_stencil_buffer = FALSE;
- int scissor_x0;
- int scissor_y0;
- int scissor_x1;
- int scissor_y1;
- CoglClipStack *entry;
- int scissor_y_start;
-
- /* If we have already flushed this state then we don't need to do
- anything */
- if (ctx->current_clip_stack_valid)
- {
- if (ctx->current_clip_stack == stack)
- return;
-
- _cogl_clip_stack_unref (ctx->current_clip_stack);
- }
-
- ctx->current_clip_stack_valid = TRUE;
- ctx->current_clip_stack = _cogl_clip_stack_ref (stack);
-
- has_clip_planes =
- ctx->private_feature_flags & COGL_PRIVATE_FEATURE_FOUR_CLIP_PLANES;
-
- if (has_clip_planes)
- disable_clip_planes ();
- disable_stencil_buffer ();
-
- /* If the stack is empty then there's nothing else to do */
- if (stack == NULL)
- {
- COGL_NOTE (CLIPPING, "Flushed empty clip stack");
-
- ctx->current_clip_stack_uses_stencil = FALSE;
- GE (ctx, glDisable (GL_SCISSOR_TEST));
- return;
- }
-
- /* Calculate the scissor rect first so that if we eventually have to
- clear the stencil buffer then the clear will be clipped to the
- intersection of all of the bounding boxes. This saves having to
- clear the whole stencil buffer */
- _cogl_clip_stack_get_bounds (stack,
- &scissor_x0, &scissor_y0,
- &scissor_x1, &scissor_y1);
-
- /* Enable scissoring as soon as possible */
- if (scissor_x0 >= scissor_x1 || scissor_y0 >= scissor_y1)
- scissor_x0 = scissor_y0 = scissor_x1 = scissor_y1 = scissor_y_start = 0;
- else
- {
- /* We store the entry coordinates in Cogl coordinate space
- * but OpenGL requires the window origin to be the bottom
- * left so we may need to convert the incoming coordinates.
- *
- * NB: Cogl forces all offscreen rendering to be done upside
- * down so in this case no conversion is needed.
- */
-
- if (cogl_is_offscreen (framebuffer))
- scissor_y_start = scissor_y0;
- else
- {
- int framebuffer_height =
- cogl_framebuffer_get_height (framebuffer);
-
- scissor_y_start = framebuffer_height - scissor_y1;
- }
- }
-
- COGL_NOTE (CLIPPING, "Flushing scissor to (%i, %i, %i, %i)",
- scissor_x0, scissor_y0,
- scissor_x1, scissor_y1);
-
- GE (ctx, glEnable (GL_SCISSOR_TEST));
- GE (ctx, glScissor (scissor_x0, scissor_y_start,
- scissor_x1 - scissor_x0,
- scissor_y1 - scissor_y0));
-
- /* Add all of the entries. This will end up adding them in the
- reverse order that they were specified but as all of the clips
- are intersecting it should work out the same regardless of the
- order */
- for (entry = stack; entry; entry = entry->parent)
- {
- switch (entry->type)
- {
- case COGL_CLIP_STACK_PATH:
- {
- CoglClipStackPath *path_entry = (CoglClipStackPath *) entry;
-
- COGL_NOTE (CLIPPING, "Adding stencil clip for path");
-
- add_stencil_clip_path (framebuffer,
- path_entry->matrix_entry,
- path_entry->path,
- using_stencil_buffer,
- TRUE);
-
- using_stencil_buffer = TRUE;
- break;
- }
- case COGL_CLIP_STACK_PRIMITIVE:
- {
- CoglClipStackPrimitive *primitive_entry =
- (CoglClipStackPrimitive *) entry;
-
- COGL_NOTE (CLIPPING, "Adding stencil clip for primitive");
-
- add_stencil_clip_primitive (framebuffer,
- primitive_entry->matrix_entry,
- primitive_entry->primitive,
- primitive_entry->bounds_x1,
- primitive_entry->bounds_y1,
- primitive_entry->bounds_x2,
- primitive_entry->bounds_y2,
- using_stencil_buffer,
- TRUE);
-
- 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)
- {
- /* 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->matrix_entry,
- 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->matrix_entry,
- rect->x0,
- rect->y0,
- rect->x1,
- rect->y1,
- !using_stencil_buffer);
- using_stencil_buffer = TRUE;
- }
- }
- 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 */
- }
- }
-
- /* Enabling clip planes is delayed to now so that they won't affect
- setting up the stencil buffer */
- if (using_clip_planes)
- enable_clip_planes ();
- ctx->current_clip_stack_uses_stencil = using_stencil_buffer;
+ ctx->driver_vtable->clip_stack_flush (stack, framebuffer);
}
diff --git a/cogl/cogl-driver.h b/cogl/cogl-driver.h
index bea53cd6..527e5ffa 100644
--- a/cogl/cogl-driver.h
+++ b/cogl/cogl-driver.h
@@ -222,6 +222,13 @@ struct _CoglDriverVtable
CoglDrawFlags flags,
CoglAttribute **attributes,
int n_attributes);
+
+ /* Flushes the clip stack to the GPU using a combination of the
+ * stencil buffer, scissor and clip plane state.
+ */
+ void
+ (* clip_stack_flush) (CoglClipStack *stack, CoglFramebuffer *framebuffer);
+
};
#endif /* __COGL_DRIVER_H */
diff --git a/cogl/driver/gl/cogl-clip-stack-gl-private.h b/cogl/driver/gl/cogl-clip-stack-gl-private.h
new file mode 100644
index 00000000..2946b3ba
--- /dev/null
+++ b/cogl/driver/gl/cogl-clip-stack-gl-private.h
@@ -0,0 +1,39 @@
+/*
+ * Cogl
+ *
+ * An object oriented GL/GLES Abstraction/Utility Layer
+ *
+ * Copyright (C) 2012 Intel Corporation.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ *
+ *
+ * Authors:
+ * Robert Bragg <robert@linux.intel.com>
+ */
+
+#ifndef _COGL_CLIP_STACK_GL_PRIVATE_H_
+#define _COGL_CLIP_STACK_GL_PRIVATE_H_
+
+#include "cogl-types.h"
+#include "cogl-framebuffer.h"
+#include "cogl-clip-stack.h"
+
+void
+_cogl_clip_stack_gl_flush (CoglClipStack *stack,
+ CoglFramebuffer *framebuffer);
+
+#endif /* _COGL_CLIP_STACK_GL_PRIVATE_H_ */
diff --git a/cogl/driver/gl/cogl-clip-stack-gl.c b/cogl/driver/gl/cogl-clip-stack-gl.c
new file mode 100644
index 00000000..2547fc9e
--- /dev/null
+++ b/cogl/driver/gl/cogl-clip-stack-gl.c
@@ -0,0 +1,633 @@
+/*
+ * Cogl
+ *
+ * An object oriented GL/GLES Abstraction/Utility Layer
+ *
+ * Copyright (C) 2007,2008,2009,2010,2011,2012 Intel Corporation.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ *
+ *
+ * Authors:
+ * Neil Roberts <neil@linux.intel.com>
+ * Robert Bragg <robert@linux.intel.com>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "cogl-context-private.h"
+#include "cogl-primitives-private.h"
+#include "cogl-pipeline-opengl-private.h"
+#include "cogl-path-private.h"
+#include "cogl-clip-stack-gl-private.h"
+
+#ifndef GL_CLIP_PLANE0
+#define GL_CLIP_PLANE0 0x3000
+#define GL_CLIP_PLANE1 0x3001
+#define GL_CLIP_PLANE2 0x3002
+#define GL_CLIP_PLANE3 0x3003
+#define GL_CLIP_PLANE4 0x3004
+#define GL_CLIP_PLANE5 0x3005
+#endif
+
+static void
+project_vertex (const CoglMatrix *modelview_projection,
+ float *vertex)
+{
+ int i;
+
+ cogl_matrix_transform_point (modelview_projection,
+ &vertex[0], &vertex[1],
+ &vertex[2], &vertex[3]);
+
+ /* Convert from homogenized coordinates */
+ for (i = 0; i < 4; i++)
+ vertex[i] /= vertex[3];
+}
+
+static void
+set_clip_plane (CoglFramebuffer *framebuffer,
+ int plane_num,
+ const float *vertex_a,
+ const float *vertex_b)
+{
+ CoglContext *ctx = framebuffer->context;
+ float planef[4];
+ double planed[4];
+ float angle;
+ CoglMatrixStack *modelview_stack =
+ _cogl_framebuffer_get_modelview_stack (framebuffer);
+ CoglMatrixStack *projection_stack =
+ _cogl_framebuffer_get_projection_stack (framebuffer);
+ CoglMatrix inverse_projection;
+
+ _cogl_matrix_stack_get_inverse (projection_stack, &inverse_projection);
+
+ /* Calculate the angle between the axes and the line crossing the
+ two points */
+ angle = atan2f (vertex_b[1] - vertex_a[1],
+ vertex_b[0] - vertex_a[0]) * (180.0/G_PI);
+
+ _cogl_matrix_stack_push (modelview_stack);
+
+ /* Load the inverse of the projection matrix so we can specify the plane
+ * in screen coordinates */
+ _cogl_matrix_stack_set (modelview_stack, &inverse_projection);
+
+ /* Rotate about point a */
+ _cogl_matrix_stack_translate (modelview_stack,
+ vertex_a[0], vertex_a[1], vertex_a[2]);
+ /* Rotate the plane by the calculated angle so that it will connect
+ the two points */
+ _cogl_matrix_stack_rotate (modelview_stack, angle, 0.0f, 0.0f, 1.0f);
+ _cogl_matrix_stack_translate (modelview_stack,
+ -vertex_a[0], -vertex_a[1], -vertex_a[2]);
+
+ /* Clip planes can only be used when a fixed function backend is in
+ use so we know we can directly push this matrix to the builtin
+ state */
+ _cogl_matrix_entry_flush_to_gl_builtins (ctx,
+ modelview_stack->last_entry,
+ COGL_MATRIX_MODELVIEW,
+ framebuffer,
+ FALSE /* don't disable flip */);
+
+ planef[0] = 0;
+ planef[1] = -1.0;
+ planef[2] = 0;
+ planef[3] = vertex_a[1];
+
+ switch (ctx->driver)
+ {
+ default:
+ g_assert_not_reached ();
+ break;
+
+ case COGL_DRIVER_GLES1:
+ GE( ctx, glClipPlanef (plane_num, planef) );
+ break;
+
+ case COGL_DRIVER_GL:
+ planed[0] = planef[0];
+ planed[1] = planef[1];
+ planed[2] = planef[2];
+ planed[3] = planef[3];
+ GE( ctx, glClipPlane (plane_num, planed) );
+ break;
+ }
+
+ _cogl_matrix_stack_pop (modelview_stack);
+}
+
+static void
+set_clip_planes (CoglFramebuffer *framebuffer,
+ CoglMatrixEntry *modelview_entry,
+ float x_1,
+ float y_1,
+ float x_2,
+ float y_2)
+{
+ CoglMatrix modelview_matrix;
+ CoglMatrixStack *projection_stack =
+ _cogl_framebuffer_get_projection_stack (framebuffer);
+ CoglMatrix projection_matrix;
+ CoglMatrix modelview_projection;
+ float signed_area;
+
+ float vertex_tl[4] = { x_1, y_1, 0, 1.0 };
+ float vertex_tr[4] = { x_2, y_1, 0, 1.0 };
+ float vertex_bl[4] = { x_1, y_2, 0, 1.0 };
+ float vertex_br[4] = { x_2, y_2, 0, 1.0 };
+
+ _cogl_matrix_stack_get (projection_stack, &projection_matrix);
+ _cogl_matrix_entry_get (modelview_entry, &modelview_matrix);
+
+ cogl_matrix_multiply (&modelview_projection,
+ &projection_matrix,
+ &modelview_matrix);
+
+ project_vertex (&modelview_projection, vertex_tl);
+ project_vertex (&modelview_projection, vertex_tr);
+ project_vertex (&modelview_projection, vertex_bl);
+ project_vertex (&modelview_projection, vertex_br);
+
+ /* Calculate the signed area of the polygon formed by the four
+ vertices so that we can know its orientation */
+ signed_area = (vertex_tl[0] * (vertex_tr[1] - vertex_bl[1])
+ + vertex_tr[0] * (vertex_br[1] - vertex_tl[1])
+ + vertex_br[0] * (vertex_bl[1] - vertex_tr[1])
+ + vertex_bl[0] * (vertex_tl[1] - vertex_br[1]));
+
+ /* Set the clip planes to form lines between all of the vertices
+ using the same orientation as we calculated */
+ if (signed_area > 0.0f)
+ {
+ /* counter-clockwise */
+ set_clip_plane (framebuffer, GL_CLIP_PLANE0, vertex_tl, vertex_bl);
+ set_clip_plane (framebuffer, GL_CLIP_PLANE1, vertex_bl, vertex_br);
+ set_clip_plane (framebuffer, GL_CLIP_PLANE2, vertex_br, vertex_tr);
+ set_clip_plane (framebuffer, GL_CLIP_PLANE3, vertex_tr, vertex_tl);
+ }
+ else
+ {
+ /* clockwise */
+ set_clip_plane (framebuffer, GL_CLIP_PLANE0, vertex_tl, vertex_tr);
+ set_clip_plane (framebuffer, GL_CLIP_PLANE1, vertex_tr, vertex_br);
+ set_clip_plane (framebuffer, GL_CLIP_PLANE2, vertex_br, vertex_bl);
+ set_clip_plane (framebuffer, GL_CLIP_PLANE3, vertex_bl, vertex_tl);
+ }
+}
+
+static void
+add_stencil_clip_rectangle (CoglFramebuffer *framebuffer,
+ CoglMatrixEntry *modelview_entry,
+ float x_1,
+ float y_1,
+ float x_2,
+ float y_2,
+ CoglBool first)
+{
+ CoglMatrixStack *projection_stack =
+ _cogl_framebuffer_get_projection_stack (framebuffer);
+ CoglContext *ctx = cogl_framebuffer_get_context (framebuffer);
+
+ /* NB: This can be called while flushing the journal so we need
+ * to be very conservative with what state we change.
+ */
+
+ _cogl_context_set_current_projection_entry (ctx,
+ projection_stack->last_entry);
+ _cogl_context_set_current_modelview_entry (ctx, modelview_entry);
+
+ if (first)
+ {
+ GE( ctx, glEnable (GL_STENCIL_TEST) );
+
+ /* Initially disallow everything */
+ GE( ctx, glClearStencil (0) );
+ GE( ctx, glClear (GL_STENCIL_BUFFER_BIT) );
+
+ /* Punch out a hole to allow the rectangle */
+ GE( ctx, glStencilFunc (GL_NEVER, 0x1, 0x1) );
+ GE( ctx, glStencilOp (GL_REPLACE, GL_REPLACE, GL_REPLACE) );
+
+ _cogl_rectangle_immediate (framebuffer,
+ ctx->stencil_pipeline,
+ x_1, y_1, x_2, y_2);
+ }
+ else
+ {
+ /* Add one to every pixel of the stencil buffer in the
+ rectangle */
+ GE( ctx, glStencilFunc (GL_NEVER, 0x1, 0x3) );
+ GE( ctx, glStencilOp (GL_INCR, GL_INCR, GL_INCR) );
+ _cogl_rectangle_immediate (framebuffer,
+ ctx->stencil_pipeline,
+ x_1, y_1, x_2, y_2);
+
+ /* Subtract one from all pixels in the stencil buffer so that
+ only pixels where both the original stencil buffer and the
+ rectangle are set will be valid */
+ GE( ctx, glStencilOp (GL_DECR, GL_DECR, GL_DECR) );
+
+ _cogl_context_set_current_projection_entry (ctx, &ctx->identity_entry);
+ _cogl_context_set_current_modelview_entry (ctx, &ctx->identity_entry);
+
+ _cogl_rectangle_immediate (framebuffer,
+ ctx->stencil_pipeline,
+ -1.0, -1.0, 1.0, 1.0);
+ }
+
+ /* Restore the stencil mode */
+ GE( ctx, glStencilFunc (GL_EQUAL, 0x1, 0x1) );
+ GE( ctx, glStencilOp (GL_KEEP, GL_KEEP, GL_KEEP) );
+}
+
+typedef void (*SilhouettePaintCallback) (CoglFramebuffer *framebuffer,
+ CoglPipeline *pipeline,
+ void *user_data);
+
+static void
+add_stencil_clip_silhouette (CoglFramebuffer *framebuffer,
+ SilhouettePaintCallback silhouette_callback,
+ CoglMatrixEntry *modelview_entry,
+ float bounds_x1,
+ float bounds_y1,
+ float bounds_x2,
+ float bounds_y2,
+ CoglBool merge,
+ CoglBool need_clear,
+ void *user_data)
+{
+ CoglMatrixStack *projection_stack =
+ _cogl_framebuffer_get_projection_stack (framebuffer);
+ CoglContext *ctx = cogl_framebuffer_get_context (framebuffer);
+
+ /* NB: This can be called while flushing the journal so we need
+ * to be very conservative with what state we change.
+ */
+
+ _cogl_context_set_current_projection_entry (ctx,
+ projection_stack->last_entry);
+ _cogl_context_set_current_modelview_entry (ctx, modelview_entry);
+
+ _cogl_pipeline_flush_gl_state (ctx->stencil_pipeline, framebuffer, FALSE, 0);
+
+ GE( ctx, glEnable (GL_STENCIL_TEST) );
+
+ GE( ctx, glColorMask (FALSE, FALSE, FALSE, FALSE) );
+ GE( ctx, glDepthMask (FALSE) );
+
+ if (merge)
+ {
+ GE (ctx, glStencilMask (2));
+ GE (ctx, glStencilFunc (GL_LEQUAL, 0x2, 0x6));
+ }
+ else
+ {
+ /* If we're not using the stencil buffer for clipping then we
+ don't need to clear the whole stencil buffer, just the area
+ that will be drawn */
+ if (need_clear)
+ /* If this is being called from the clip stack code then it
+ will have set up a scissor for the minimum bounding box of
+ all of the clips. That box will likely mean that this
+ _cogl_clear won't need to clear the entire
+ buffer. _cogl_framebuffer_clear_without_flush4f is used instead
+ of cogl_clear because it won't try to flush the journal */
+ _cogl_framebuffer_clear_without_flush4f (framebuffer,
+ COGL_BUFFER_BIT_STENCIL,
+ 0, 0, 0, 0);
+ else
+ {
+ /* Just clear the bounding box */
+ GE( ctx, glStencilMask (~(GLuint) 0) );
+ GE( ctx, glStencilOp (GL_ZERO, GL_ZERO, GL_ZERO) );
+ _cogl_rectangle_immediate (framebuffer,
+ ctx->stencil_pipeline,
+ bounds_x1, bounds_y1,
+ bounds_x2, bounds_y2);
+ }
+ GE (ctx, glStencilMask (1));
+ GE (ctx, glStencilFunc (GL_LEQUAL, 0x1, 0x3));
+ }
+
+ GE (ctx, glStencilOp (GL_INVERT, GL_INVERT, GL_INVERT));
+
+ silhouette_callback (framebuffer, ctx->stencil_pipeline, user_data);
+
+ 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 (ctx, glStencilMask (3));
+ GE (ctx, glStencilFunc (GL_NEVER, 0x2, 0x3));
+ GE (ctx, glStencilOp (GL_DECR, GL_DECR, GL_DECR));
+ /* Decrement all of the bits twice so that only pixels where the
+ value is 3 will remain */
+
+ _cogl_context_set_current_projection_entry (ctx, &ctx->identity_entry);
+ _cogl_context_set_current_modelview_entry (ctx, &ctx->identity_entry);
+
+ _cogl_rectangle_immediate (framebuffer, ctx->stencil_pipeline,
+ -1.0, -1.0, 1.0, 1.0);
+ _cogl_rectangle_immediate (framebuffer, ctx->stencil_pipeline,
+ -1.0, -1.0, 1.0, 1.0);
+ }
+
+ GE (ctx, glStencilMask (~(GLuint) 0));
+ GE (ctx, glDepthMask (TRUE));
+ GE (ctx, glColorMask (TRUE, TRUE, TRUE, TRUE));
+
+ GE (ctx, glStencilFunc (GL_EQUAL, 0x1, 0x1));
+ GE (ctx, glStencilOp (GL_KEEP, GL_KEEP, GL_KEEP));
+}
+
+static void
+paint_path_silhouette (CoglFramebuffer *framebuffer,
+ CoglPipeline *pipeline,
+ void *user_data)
+{
+ CoglPath *path = user_data;
+ if (path->data->path_nodes->len >= 3)
+ _cogl_path_fill_nodes (path,
+ framebuffer,
+ pipeline,
+ COGL_DRAW_SKIP_JOURNAL_FLUSH |
+ COGL_DRAW_SKIP_PIPELINE_VALIDATION |
+ COGL_DRAW_SKIP_FRAMEBUFFER_FLUSH);
+}
+
+static void
+add_stencil_clip_path (CoglFramebuffer *framebuffer,
+ CoglMatrixEntry *modelview_entry,
+ CoglPath *path,
+ CoglBool merge,
+ CoglBool need_clear)
+{
+ CoglPathData *data = path->data;
+ add_stencil_clip_silhouette (framebuffer,
+ paint_path_silhouette,
+ modelview_entry,
+ 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_silhouette (CoglFramebuffer *framebuffer,
+ CoglPipeline *pipeline,
+ void *user_data)
+{
+ _cogl_framebuffer_draw_primitive (framebuffer,
+ pipeline,
+ user_data,
+ COGL_DRAW_SKIP_JOURNAL_FLUSH |
+ COGL_DRAW_SKIP_PIPELINE_VALIDATION |
+ COGL_DRAW_SKIP_FRAMEBUFFER_FLUSH);
+}
+
+static void
+add_stencil_clip_primitive (CoglFramebuffer *framebuffer,
+ CoglMatrixEntry *modelview_entry,
+ CoglPrimitive *primitive,
+ float bounds_x1,
+ float bounds_y1,
+ float bounds_x2,
+ float bounds_y2,
+ CoglBool merge,
+ CoglBool need_clear)
+{
+ add_stencil_clip_silhouette (framebuffer,
+ paint_primitive_silhouette,
+ modelview_entry,
+ bounds_x1,
+ bounds_y1,
+ bounds_x2,
+ bounds_y2,
+ merge,
+ need_clear,
+ primitive);
+}
+
+static void
+enable_clip_planes (CoglContext *ctx)
+{
+ GE( ctx, glEnable (GL_CLIP_PLANE0) );
+ GE( ctx, glEnable (GL_CLIP_PLANE1) );
+ GE( ctx, glEnable (GL_CLIP_PLANE2) );
+ GE( ctx, glEnable (GL_CLIP_PLANE3) );
+}
+
+static void
+disable_clip_planes (CoglContext *ctx)
+{
+ GE( ctx, glDisable (GL_CLIP_PLANE3) );
+ GE( ctx, glDisable (GL_CLIP_PLANE2) );
+ GE( ctx, glDisable (GL_CLIP_PLANE1) );
+ GE( ctx, glDisable (GL_CLIP_PLANE0) );
+}
+
+void
+_cogl_clip_stack_gl_flush (CoglClipStack *stack,
+ CoglFramebuffer *framebuffer)
+{
+ CoglContext *ctx = framebuffer->context;
+ int has_clip_planes;
+ CoglBool using_clip_planes = FALSE;
+ CoglBool using_stencil_buffer = FALSE;
+ int scissor_x0;
+ int scissor_y0;
+ int scissor_x1;
+ int scissor_y1;
+ CoglClipStack *entry;
+ int scissor_y_start;
+
+ /* If we have already flushed this state then we don't need to do
+ anything */
+ if (ctx->current_clip_stack_valid)
+ {
+ if (ctx->current_clip_stack == stack)
+ return;
+
+ _cogl_clip_stack_unref (ctx->current_clip_stack);
+ }
+
+ ctx->current_clip_stack_valid = TRUE;
+ ctx->current_clip_stack = _cogl_clip_stack_ref (stack);
+
+ has_clip_planes =
+ ctx->private_feature_flags & COGL_PRIVATE_FEATURE_FOUR_CLIP_PLANES;
+
+ if (has_clip_planes)
+ disable_clip_planes (ctx);
+ GE( ctx, glDisable (GL_STENCIL_TEST) );
+
+ /* If the stack is empty then there's nothing else to do */
+ if (stack == NULL)
+ {
+ COGL_NOTE (CLIPPING, "Flushed empty clip stack");
+
+ ctx->current_clip_stack_uses_stencil = FALSE;
+ GE (ctx, glDisable (GL_SCISSOR_TEST));
+ return;
+ }
+
+ /* Calculate the scissor rect first so that if we eventually have to
+ clear the stencil buffer then the clear will be clipped to the
+ intersection of all of the bounding boxes. This saves having to
+ clear the whole stencil buffer */
+ _cogl_clip_stack_get_bounds (stack,
+ &scissor_x0, &scissor_y0,
+ &scissor_x1, &scissor_y1);
+
+ /* Enable scissoring as soon as possible */
+ if (scissor_x0 >= scissor_x1 || scissor_y0 >= scissor_y1)
+ scissor_x0 = scissor_y0 = scissor_x1 = scissor_y1 = scissor_y_start = 0;
+ else
+ {
+ /* We store the entry coordinates in Cogl coordinate space
+ * but OpenGL requires the window origin to be the bottom
+ * left so we may need to convert the incoming coordinates.
+ *
+ * NB: Cogl forces all offscreen rendering to be done upside
+ * down so in this case no conversion is needed.
+ */
+
+ if (cogl_is_offscreen (framebuffer))
+ scissor_y_start = scissor_y0;
+ else
+ {
+ int framebuffer_height =
+ cogl_framebuffer_get_height (framebuffer);
+
+ scissor_y_start = framebuffer_height - scissor_y1;
+ }
+ }
+
+ COGL_NOTE (CLIPPING, "Flushing scissor to (%i, %i, %i, %i)",
+ scissor_x0, scissor_y0,
+ scissor_x1, scissor_y1);
+
+ GE (ctx, glEnable (GL_SCISSOR_TEST));
+ GE (ctx, glScissor (scissor_x0, scissor_y_start,
+ scissor_x1 - scissor_x0,
+ scissor_y1 - scissor_y0));
+
+ /* Add all of the entries. This will end up adding them in the
+ reverse order that they were specified but as all of the clips
+ are intersecting it should work out the same regardless of the
+ order */
+ for (entry = stack; entry; entry = entry->parent)
+ {
+ switch (entry->type)
+ {
+ case COGL_CLIP_STACK_PATH:
+ {
+ CoglClipStackPath *path_entry = (CoglClipStackPath *) entry;
+
+ COGL_NOTE (CLIPPING, "Adding stencil clip for path");
+
+ add_stencil_clip_path (framebuffer,
+ path_entry->matrix_entry,
+ path_entry->path,
+ using_stencil_buffer,
+ TRUE);
+
+ using_stencil_buffer = TRUE;
+ break;
+ }
+ case COGL_CLIP_STACK_PRIMITIVE:
+ {
+ CoglClipStackPrimitive *primitive_entry =
+ (CoglClipStackPrimitive *) entry;
+
+ COGL_NOTE (CLIPPING, "Adding stencil clip for primitive");
+
+ add_stencil_clip_primitive (framebuffer,
+ primitive_entry->matrix_entry,
+ primitive_entry->primitive,
+ primitive_entry->bounds_x1,
+ primitive_entry->bounds_y1,
+ primitive_entry->bounds_x2,
+ primitive_entry->bounds_y2,
+ using_stencil_buffer,
+ TRUE);
+
+ 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)
+ {
+ /* 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->matrix_entry,
+ 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->matrix_entry,
+ rect->x0,
+ rect->y0,
+ rect->x1,
+ rect->y1,
+ !using_stencil_buffer);
+ using_stencil_buffer = TRUE;
+ }
+ }
+ 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 */
+ }
+ }
+
+ /* Enabling clip planes is delayed to now so that they won't affect
+ setting up the stencil buffer */
+ if (using_clip_planes)
+ enable_clip_planes (ctx);
+
+ ctx->current_clip_stack_uses_stencil = using_stencil_buffer;
+}
diff --git a/cogl/driver/gl/gl/cogl-driver-gl.c b/cogl/driver/gl/gl/cogl-driver-gl.c
index c4674e37..aadef36e 100644
--- a/cogl/driver/gl/gl/cogl-driver-gl.c
+++ b/cogl/driver/gl/gl/cogl-driver-gl.c
@@ -36,6 +36,7 @@
#include "cogl-framebuffer-gl-private.h"
#include "cogl-texture-2d-gl-private.h"
#include "cogl-attribute-gl-private.h"
+#include "cogl-clip-stack-gl-private.h"
static CoglBool
_cogl_driver_pixel_format_from_gl_internal (CoglContext *context,
@@ -549,4 +550,5 @@ _cogl_driver_gl =
_cogl_texture_2d_gl_copy_from_bitmap,
_cogl_texture_2d_gl_get_data,
_cogl_gl_flush_attributes_state,
+ _cogl_clip_stack_gl_flush,
};
diff --git a/cogl/driver/gl/gles/cogl-driver-gles.c b/cogl/driver/gl/gles/cogl-driver-gles.c
index b5487fbf..e2dbee5a 100644
--- a/cogl/driver/gl/gles/cogl-driver-gles.c
+++ b/cogl/driver/gl/gles/cogl-driver-gles.c
@@ -35,6 +35,7 @@
#include "cogl-framebuffer-gl-private.h"
#include "cogl-texture-2d-gl-private.h"
#include "cogl-attribute-gl-private.h"
+#include "cogl-clip-stack-gl-private.h"
#ifndef GL_UNSIGNED_INT_24_8
#define GL_UNSIGNED_INT_24_8 0x84FA
@@ -367,4 +368,5 @@ _cogl_driver_gles =
_cogl_texture_2d_gl_copy_from_bitmap,
NULL, /* texture_2d_get_data */
_cogl_gl_flush_attributes_state,
+ _cogl_clip_stack_gl_flush,
};