[cogl/wip/rib/master-next: 9/36] clip: Adds cogl_clip_push_primitive API



commit 044ed65e11e46d2a18fd1eb143a9bd39c55c8d6c
Author: Robert Bragg <robert linux intel com>
Date:   Mon Oct 3 14:39:05 2011 +0100

    clip: Adds cogl_clip_push_primitive API
    
    This adds a new experimental function, cogl_clip_push_primitive, that
    allows you to push a CoglPrimitive onto the clip stack. The primitive
    should describe a flat 2D shape and the geometry shouldn't include any
    self intersections. When pushing a primitive you also need to tell
    Cogl what the bounding box of that shape is (in shape local coordinates)
    so that Cogl is able to efficiently update the required region of the
    stencil buffer.

 cogl/cogl-clip-stack.c |  250 ++++++++++++++++++++++++++++++++++++------------
 cogl/cogl-clip-stack.h |   29 ++++++-
 cogl/cogl-clip-state.c |   26 +++++
 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 c01a74c..c0786e0 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 6188f51..0a77a18 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 8ef3f4b..1f23471 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 240fa2a..4cebfa2 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:
  *



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]