Separate out CoglClipStackState from cogl-clip-stack.c
authorNeil Roberts <neil@linux.intel.com>
Wed, 14 Apr 2010 18:41:08 +0000 (19:41 +0100)
committerNeil Roberts <neil@linux.intel.com>
Thu, 15 Apr 2010 13:51:00 +0000 (14:51 +0100)
CoglClipStackState has now been renamed to CoglClipState and is moved
to a separate file. CoglClipStack now just maintains a stack and
doesn't worry about the rest of the state. CoglClipStack sill contains
the code to flush the stack to GL.

clutter/cogl/cogl/Makefile.am
clutter/cogl/cogl/cogl-clip-stack.c
clutter/cogl/cogl/cogl-clip-stack.h
clutter/cogl/cogl/cogl-clip-state.c [new file with mode: 0644]
clutter/cogl/cogl/cogl-clip-state.h [new file with mode: 0644]
clutter/cogl/cogl/cogl-framebuffer-private.h
clutter/cogl/cogl/cogl-framebuffer.c
clutter/cogl/cogl/cogl-path.c
clutter/cogl/cogl/cogl.c

index ac93439..058551d 100644 (file)
@@ -103,6 +103,8 @@ cogl_sources_c = \
        $(srcdir)/cogl-bitmap-pixbuf.c                  \
        $(srcdir)/cogl-clip-stack.h                     \
        $(srcdir)/cogl-clip-stack.c                     \
+       $(srcdir)/cogl-clip-state.h                     \
+       $(srcdir)/cogl-clip-state.c                     \
        $(srcdir)/cogl-feature-private.h                \
        $(srcdir)/cogl-feature-private.c                \
        $(srcdir)/cogl-fixed.c                          \
index 37c9d02..83e95af 100644 (file)
@@ -3,7 +3,7 @@
  *
  * An object oriented GL/GLES Abstraction/Utility Layer
  *
- * Copyright (C) 2007,2008,2009 Intel Corporation.
+ * Copyright (C) 2007,2008,2009,2010 Intel Corporation.
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -40,8 +40,6 @@
 #include "cogl-util.h"
 #include "cogl-path-private.h"
 
-typedef struct _CoglClipStack CoglClipStack;
-
 typedef struct _CoglClipStackEntry CoglClipStackEntry;
 typedef struct _CoglClipStackEntryRect CoglClipStackEntryRect;
 typedef struct _CoglClipStackEntryWindowRect CoglClipStackEntryWindowRect;
@@ -402,27 +400,16 @@ _cogl_clip_stack_push_entry (CoglClipStack *clip_stack,
 }
 
 void
-cogl_clip_push_window_rectangle (int x_offset,
-                                int y_offset,
-                                int width,
-                                int height)
+_cogl_clip_stack_push_window_rectangle (CoglClipStack *stack,
+                                        int x_offset,
+                                        int y_offset,
+                                        int width,
+                                        int height)
 {
-  CoglHandle framebuffer;
-  CoglClipStackState *clip_state;
-  CoglClipStack *stack;
   CoglClipStackEntryWindowRect *entry;
 
   _COGL_GET_CONTEXT (ctx, NO_RETVAL);
 
-  /* We don't log clip stack changes in the journal so we must flush
-   * it before making modifications */
-  _cogl_journal_flush ();
-
-  framebuffer = _cogl_get_framebuffer ();
-  clip_state = _cogl_framebuffer_get_clip_state (framebuffer);
-
-  stack = clip_state->stacks->data;
-
   entry = _cogl_clip_stack_push_entry (stack,
                                        sizeof (CoglClipStackEntryWindowRect),
                                        COGL_CLIP_STACK_WINDOW_RECT);
@@ -431,137 +418,18 @@ cogl_clip_push_window_rectangle (int x_offset,
   entry->x1 = x_offset + width;
   entry->y0 = y_offset;
   entry->y1 = y_offset + height;
-
-  clip_state->stack_dirty = TRUE;
 }
 
-/* XXX: This is deprecated API */
 void
-cogl_clip_push_window_rect (float x_offset,
-                           float y_offset,
-                           float width,
-                           float height)
-{
-  cogl_clip_push_window_rectangle (x_offset, y_offset, width, height);
-}
-
-/* Scale from OpenGL normalized device coordinates (ranging from -1 to 1)
- * to Cogl window/framebuffer coordinates (ranging from 0 to buffer-size) with
- * (0,0) being top left. */
-#define VIEWPORT_TRANSFORM_X(x, vp_origin_x, vp_width) \
-    (  ( ((x) + 1.0) * ((vp_width) / 2.0) ) + (vp_origin_x)  )
-/* Note: for Y we first flip all coordinates around the X axis while in
- * normalized device coodinates */
-#define VIEWPORT_TRANSFORM_Y(y, vp_origin_y, vp_height) \
-    (  ( ((-(y)) + 1.0) * ((vp_height) / 2.0) ) + (vp_origin_y)  )
-
-/* Transform a homogeneous vertex position from model space to Cogl
- * window coordinates (with 0,0 being top left) */
-static void
-transform_point (CoglMatrix *matrix_mv,
-                 CoglMatrix *matrix_p,
-                 float *viewport,
-                 float *x,
-                 float *y)
-{
-  float z = 0;
-  float w = 1;
-
-  /* Apply the modelview matrix transform */
-  cogl_matrix_transform_point (matrix_mv, x, y, &z, &w);
-
-  /* Apply the projection matrix transform */
-  cogl_matrix_transform_point (matrix_p, x, y, &z, &w);
-
-  /* Perform perspective division */
-  *x /= w;
-  *y /= w;
-
-  /* Apply viewport transform */
-  *x = VIEWPORT_TRANSFORM_X (*x, viewport[0], viewport[2]);
-  *y = VIEWPORT_TRANSFORM_Y (*y, viewport[1], viewport[3]);
-}
-
-#undef VIEWPORT_SCALE_X
-#undef VIEWPORT_SCALE_Y
-
-/* Try to push a rectangle given in object coordinates as a rectangle in window
- * coordinates instead of object coordinates */
-gboolean
-try_pushing_rect_as_window_rect (float x_1,
-                                float y_1,
+_cogl_clip_stack_push_rectangle (CoglClipStack *stack,
+                                 float x_1,
+                                 float y_1,
                                  float x_2,
-                                 float y_2)
-{
-  CoglMatrix matrix;
-  CoglMatrix matrix_p;
-  float v[4];
-
-  cogl_get_modelview_matrix (&matrix);
-
-  /* If the modelview meets these constraints then a transformed rectangle
-   * should still be a rectangle when it reaches screen coordinates.
-   *
-   * FIXME: we are are making certain assumptions about the projection
-   * matrix a.t.m and should really be looking at the combined modelview
-   * and projection matrix.
-   * FIXME: we don't consider rotations that are a multiple of 90 degrees
-   * which could be quite common.
-   */
-  if (matrix.xy != 0 || matrix.xz != 0 ||
-      matrix.yx != 0 || matrix.yz != 0 ||
-      matrix.zx != 0 || matrix.zy != 0)
-    return FALSE;
-
-  cogl_get_projection_matrix (&matrix_p);
-  cogl_get_viewport (v);
-
-  transform_point (&matrix, &matrix_p, v, &x_1, &y_1);
-  transform_point (&matrix, &matrix_p, v, &x_2, &y_2);
-
-  /* Consider that the modelview matrix may flip the rectangle
-   * along the x or y axis... */
-#define SWAP(A,B) do { float tmp = B; B = A; A = tmp; } while (0)
-  if (x_1 > x_2)
-    SWAP (x_1, x_2);
-  if (y_1 > y_2)
-    SWAP (y_1, y_2);
-#undef SWAP
-
-  cogl_clip_push_window_rectangle (COGL_UTIL_NEARBYINT (x_1),
-                                   COGL_UTIL_NEARBYINT (y_1),
-                                   COGL_UTIL_NEARBYINT (x_2 - x_1),
-                                   COGL_UTIL_NEARBYINT (y_2 - y_1));
-  return TRUE;
-}
-
-void
-cogl_clip_push_rectangle (float x_1,
-                          float y_1,
-                          float x_2,
-                          float y_2)
+                                 float y_2,
+                                 const CoglMatrix *modelview_matrix)
 {
-  CoglHandle framebuffer;
-  CoglClipStackState *clip_state;
-  CoglClipStack *stack;
   CoglClipStackEntryRect *entry;
 
-  _COGL_GET_CONTEXT (ctx, NO_RETVAL);
-
-  /* We don't log clip stack changes in the journal so we must flush
-   * it before making modifications */
-  _cogl_journal_flush ();
-
-  /* Try and catch window space rectangles so we can redirect to
-   * cogl_clip_push_window_rect which will use scissoring. */
-  if (try_pushing_rect_as_window_rect (x_1, y_1, x_2, y_2))
-    return;
-
-  framebuffer = _cogl_get_framebuffer ();
-  clip_state = _cogl_framebuffer_get_clip_state (framebuffer);
-
-  stack = clip_state->stacks->data;
-
   /* Make a new entry */
   entry = _cogl_clip_stack_push_entry (stack,
                                        sizeof (CoglClipStackEntryRect),
@@ -572,60 +440,23 @@ cogl_clip_push_rectangle (float x_1,
   entry->x1 = x_2;
   entry->y1 = y_2;
 
-  cogl_get_modelview_matrix (&entry->matrix);
-
-  clip_state->stack_dirty = TRUE;
-}
-
-/* XXX: Deprecated API */
-void
-cogl_clip_push (float x_offset,
-               float y_offset,
-               float width,
-               float height)
-{
-  cogl_clip_push_rectangle (x_offset,
-                            y_offset,
-                            x_offset + width,
-                            y_offset + height);
+  entry->matrix = *modelview_matrix;
 }
 
 void
-cogl_clip_push_from_path_preserve (void)
+_cogl_clip_stack_push_from_path (CoglClipStack *stack,
+                                 CoglHandle path,
+                                 const CoglMatrix *modelview_matrix)
 {
-  CoglHandle framebuffer;
-  CoglClipStackState *clip_state;
-  CoglClipStack *stack;
   CoglClipStackEntryPath *entry;
 
-  _COGL_GET_CONTEXT (ctx, NO_RETVAL);
-
-  /* We don't log clip stack changes in the journal so we must flush
-   * it before making modifications */
-  _cogl_journal_flush ();
-
-  framebuffer = _cogl_get_framebuffer ();
-  clip_state = _cogl_framebuffer_get_clip_state (framebuffer);
-
-  stack = clip_state->stacks->data;
-
   entry = _cogl_clip_stack_push_entry (stack,
                                        sizeof (CoglClipStackEntryPath),
                                        COGL_CLIP_STACK_PATH);
 
-  entry->path = cogl_path_copy (cogl_path_get ());
-
-  cogl_get_modelview_matrix (&entry->matrix);
+  entry->path = cogl_path_copy (path);
 
-  clip_state->stack_dirty = TRUE;
-}
-
-void
-cogl_clip_push_from_path (void)
-{
-  cogl_clip_push_from_path_preserve ();
-
-  cogl_path_new ();
+  entry->matrix = *modelview_matrix;
 }
 
 static void
@@ -660,18 +491,11 @@ _cogl_clip_stack_entry_unref (CoglClipStackEntry *entry)
     }
 }
 
-static void
-_cogl_clip_pop_real (CoglClipStackState *clip_state)
+void
+_cogl_clip_stack_pop (CoglClipStack *stack)
 {
-  CoglClipStack *stack;
   CoglClipStackEntry *entry;
 
-  /* We don't log clip stack changes in the journal so we must flush
-   * it before making modifications */
-  _cogl_journal_flush ();
-
-  stack = clip_state->stacks->data;
-
   g_return_if_fail (stack->stack_top != NULL);
 
   /* To pop we are moving the top of the stack to the old top's parent
@@ -687,28 +511,12 @@ _cogl_clip_pop_real (CoglClipStackState *clip_state)
   if (stack->stack_top)
     stack->stack_top->ref_count++;
   _cogl_clip_stack_entry_unref (entry);
-
-  clip_state->stack_dirty = TRUE;
-}
-
-void
-cogl_clip_pop (void)
-{
-  CoglHandle framebuffer;
-  CoglClipStackState *clip_state;
-
-  _COGL_GET_CONTEXT (ctx, NO_RETVAL);
-
-  framebuffer = _cogl_get_framebuffer ();
-  clip_state = _cogl_framebuffer_get_clip_state (framebuffer);
-
-  _cogl_clip_pop_real (clip_state);
 }
 
 void
-_cogl_flush_clip_state (CoglClipStackState *clip_state)
+_cogl_clip_stack_flush (CoglClipStack *stack,
+                        gboolean *stencil_used_p)
 {
-  CoglClipStack *stack;
   int has_clip_planes;
   gboolean using_clip_planes = FALSE;
   gboolean using_stencil_buffer = FALSE;
@@ -720,26 +528,8 @@ _cogl_flush_clip_state (CoglClipStackState *clip_state)
     _cogl_framebuffer_get_modelview_stack (_cogl_get_framebuffer ());
   CoglClipStackEntry *entry;
 
-  if (!clip_state->stack_dirty)
-    return;
-
-  /* The current primitive journal does not support tracking changes to the
-   * clip stack...  */
-  _cogl_journal_flush ();
-
-  /* XXX: the handling of clipping is quite complex. It may involve use of
-   * the Cogl Journal or other Cogl APIs which may end up recursively
-   * wanting to ensure the clip state is flushed. We need to ensure we
-   * don't recurse infinitely...
-   */
-  clip_state->stack_dirty = FALSE;
-
   has_clip_planes = cogl_features_available (COGL_FEATURE_FOUR_CLIP_PLANES);
 
-  stack = clip_state->stacks->data;
-
-  clip_state->stencil_used = FALSE;
-
   disable_clip_planes ();
   disable_stencil_buffer ();
   GE (glDisable (GL_SCISSOR_TEST));
@@ -854,112 +644,27 @@ _cogl_flush_clip_state (CoglClipStackState *clip_state)
                      scissor_y1 - scissor_y0));
     }
 
-  clip_state->stencil_used = using_stencil_buffer;
-}
-
-/* XXX: This should never have been made public API! */
-void
-cogl_clip_ensure (void)
-{
-  CoglClipStackState *clip_state;
-
-  clip_state = _cogl_framebuffer_get_clip_state (_cogl_get_framebuffer ());
-  _cogl_flush_clip_state (clip_state);
+  *stencil_used_p = using_stencil_buffer;
 }
 
-static void
-_cogl_clip_stack_save_real (CoglClipStackState *clip_state)
+CoglClipStack *
+_cogl_clip_stack_new (void)
 {
   CoglClipStack *stack;
 
-  /* We don't log clip stack changes in the journal so we must flush
-   * it before making modifications */
-  _cogl_journal_flush ();
-
   stack = g_slice_new (CoglClipStack);
   stack->stack_top = NULL;
 
-  clip_state->stacks = g_slist_prepend (clip_state->stacks, stack);
-  clip_state->stack_dirty = TRUE;
+  return stack;
 }
 
 void
-cogl_clip_stack_save (void)
+_cogl_clip_stack_free (CoglClipStack *stack)
 {
-  CoglHandle framebuffer;
-  CoglClipStackState *clip_state;
-
-  _COGL_GET_CONTEXT (ctx, NO_RETVAL);
-
-  framebuffer = _cogl_get_framebuffer ();
-  clip_state = _cogl_framebuffer_get_clip_state (framebuffer);
-
-  _cogl_clip_stack_save_real (clip_state);
-}
-
-static void
-_cogl_clip_stack_restore_real (CoglClipStackState *clip_state)
-{
-  CoglClipStack *stack;
-
-  g_return_if_fail (clip_state->stacks != NULL);
-
-  /* We don't log clip stack changes in the journal so we must flush
-   * it before making modifications */
-  _cogl_journal_flush ();
-
-  stack = clip_state->stacks->data;
-
-  /* Free the stack. We only need to unref the top node and this
+  /* We only need to unref the top node and this
      should end up freeing all of the parents if need be */
   if (stack->stack_top)
     _cogl_clip_stack_entry_unref (stack->stack_top);
 
-  /* Revert to an old stack */
   g_slice_free (CoglClipStack, stack);
-  clip_state->stacks = g_slist_delete_link (clip_state->stacks,
-                                            clip_state->stacks);
-
-  clip_state->stack_dirty = TRUE;
-}
-
-void
-cogl_clip_stack_restore (void)
-{
-  CoglHandle framebuffer;
-  CoglClipStackState *clip_state;
-
-  _COGL_GET_CONTEXT (ctx, NO_RETVAL);
-
-  framebuffer = _cogl_get_framebuffer ();
-  clip_state = _cogl_framebuffer_get_clip_state (framebuffer);
-
-  _cogl_clip_stack_restore_real (clip_state);
-}
-
-void
-_cogl_clip_stack_state_init (CoglClipStackState *clip_state)
-{
-  _COGL_GET_CONTEXT (ctx, NO_RETVAL);
-
-  clip_state->stacks = NULL;
-  clip_state->stack_dirty = TRUE;
-
-  /* Add an intial stack */
-  _cogl_clip_stack_save_real (clip_state);
 }
-
-void
-_cogl_clip_stack_state_destroy (CoglClipStackState *clip_state)
-{
-  /* Destroy all of the stacks */
-  while (clip_state->stacks)
-    _cogl_clip_stack_restore_real (clip_state);
-}
-
-void
-_cogl_clip_stack_state_dirty (CoglClipStackState *clip_state)
-{
-  clip_state->stack_dirty = TRUE;
-}
-
index 43a4105..508cea9 100644 (file)
@@ -3,7 +3,7 @@
  *
  * An object oriented GL/GLES Abstraction/Utility Layer
  *
- * Copyright (C) 2007,2008,2009 Intel Corporation.
+ * Copyright (C) 2007,2008,2009,2010 Intel Corporation.
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
 #ifndef __COGL_CLIP_STACK_H
 #define __COGL_CLIP_STACK_H
 
-typedef struct _CoglClipStackState CoglClipStackState;
+typedef struct _CoglClipStack CoglClipStack;
 
-struct _CoglClipStackState
-{
-  /* Stack of stacks */
-  GSList *stacks;
+CoglClipStack *
+_cogl_clip_stack_new (void);
 
-  gboolean stack_dirty;
-  gboolean stencil_used;
-};
+void
+_cogl_clip_stack_free (CoglClipStack *stack);
 
 void
-_cogl_clip_stack_state_init (CoglClipStackState *state);
+_cogl_clip_stack_push_window_rectangle (CoglClipStack *stack,
+                                        int x_offset,
+                                        int y_offset,
+                                        int width,
+                                        int height);
 
 void
-_cogl_clip_stack_state_destroy (CoglClipStackState *state);
+_cogl_clip_stack_push_rectangle (CoglClipStack *stack,
+                                 float x_1,
+                                 float y_1,
+                                 float x_2,
+                                 float y_2,
+                                 const CoglMatrix *modelview_matrix);
 
 void
-_cogl_clip_stack_state_dirty (CoglClipStackState *state);
+_cogl_clip_stack_push_from_path (CoglClipStack *stack,
+                                 CoglHandle path,
+                                 const CoglMatrix *modelview_matrix);
+void
+_cogl_clip_stack_pop (CoglClipStack *stack);
 
 void
-_cogl_flush_clip_state (CoglClipStackState *clip_state);
+_cogl_clip_stack_flush (CoglClipStack *stack,
+                        gboolean *stencil_used_p);
 
 #endif /* __COGL_CLIP_STACK_H */
diff --git a/clutter/cogl/cogl/cogl-clip-state.c b/clutter/cogl/cogl/cogl-clip-state.c
new file mode 100644 (file)
index 0000000..c5b7442
--- /dev/null
@@ -0,0 +1,405 @@
+/*
+ * Cogl
+ *
+ * An object oriented GL/GLES Abstraction/Utility Layer
+ *
+ * Copyright (C) 2007,2008,2009,2010 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/>.
+ *
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <string.h>
+#include <math.h>
+
+#include <glib.h>
+
+#include "cogl.h"
+#include "cogl-clip-stack.h"
+#include "cogl-clip-state.h"
+#include "cogl-context.h"
+#include "cogl-internal.h"
+#include "cogl-framebuffer-private.h"
+#include "cogl-journal-private.h"
+#include "cogl-util.h"
+
+void
+cogl_clip_push_window_rectangle (int x_offset,
+                                 int y_offset,
+                                 int width,
+                                 int height)
+{
+  CoglHandle framebuffer;
+  CoglClipState *clip_state;
+  CoglClipStack *stack;
+
+  _COGL_GET_CONTEXT (ctx, NO_RETVAL);
+
+  /* We don't log clip stack changes in the journal so we must flush
+   * it before making modifications */
+  _cogl_journal_flush ();
+
+  framebuffer = _cogl_get_framebuffer ();
+  clip_state = _cogl_framebuffer_get_clip_state (framebuffer);
+
+  stack = clip_state->stacks->data;
+
+  _cogl_clip_stack_push_window_rectangle (stack, x_offset, y_offset,
+                                          width, height);
+
+  clip_state->stack_dirty = TRUE;
+}
+
+/* XXX: This is deprecated API */
+void
+cogl_clip_push_window_rect (float x_offset,
+                            float y_offset,
+                            float width,
+                            float height)
+{
+  cogl_clip_push_window_rectangle (x_offset, y_offset, width, height);
+}
+
+/* Scale from OpenGL normalized device coordinates (ranging from -1 to 1)
+ * to Cogl window/framebuffer coordinates (ranging from 0 to buffer-size) with
+ * (0,0) being top left. */
+#define VIEWPORT_TRANSFORM_X(x, vp_origin_x, vp_width) \
+    (  ( ((x) + 1.0) * ((vp_width) / 2.0) ) + (vp_origin_x)  )
+/* Note: for Y we first flip all coordinates around the X axis while in
+ * normalized device coodinates */
+#define VIEWPORT_TRANSFORM_Y(y, vp_origin_y, vp_height) \
+    (  ( ((-(y)) + 1.0) * ((vp_height) / 2.0) ) + (vp_origin_y)  )
+
+/* Transform a homogeneous vertex position from model space to Cogl
+ * window coordinates (with 0,0 being top left) */
+static void
+transform_point (CoglMatrix *matrix_mv,
+                 CoglMatrix *matrix_p,
+                 float *viewport,
+                 float *x,
+                 float *y)
+{
+  float z = 0;
+  float w = 1;
+
+  /* Apply the modelview matrix transform */
+  cogl_matrix_transform_point (matrix_mv, x, y, &z, &w);
+
+  /* Apply the projection matrix transform */
+  cogl_matrix_transform_point (matrix_p, x, y, &z, &w);
+
+  /* Perform perspective division */
+  *x /= w;
+  *y /= w;
+
+  /* Apply viewport transform */
+  *x = VIEWPORT_TRANSFORM_X (*x, viewport[0], viewport[2]);
+  *y = VIEWPORT_TRANSFORM_Y (*y, viewport[1], viewport[3]);
+}
+
+#undef VIEWPORT_SCALE_X
+#undef VIEWPORT_SCALE_Y
+
+/* Try to push a rectangle given in object coordinates as a rectangle in window
+ * coordinates instead of object coordinates */
+gboolean
+try_pushing_rect_as_window_rect (float x_1,
+                                 float y_1,
+                                 float x_2,
+                                 float y_2)
+{
+  CoglMatrix matrix;
+  CoglMatrix matrix_p;
+  float v[4];
+
+  cogl_get_modelview_matrix (&matrix);
+
+  /* If the modelview meets these constraints then a transformed rectangle
+   * should still be a rectangle when it reaches screen coordinates.
+   *
+   * FIXME: we are are making certain assumptions about the projection
+   * matrix a.t.m and should really be looking at the combined modelview
+   * and projection matrix.
+   * FIXME: we don't consider rotations that are a multiple of 90 degrees
+   * which could be quite common.
+   */
+  if (matrix.xy != 0 || matrix.xz != 0 ||
+      matrix.yx != 0 || matrix.yz != 0 ||
+      matrix.zx != 0 || matrix.zy != 0)
+    return FALSE;
+
+  cogl_get_projection_matrix (&matrix_p);
+  cogl_get_viewport (v);
+
+  transform_point (&matrix, &matrix_p, v, &x_1, &y_1);
+  transform_point (&matrix, &matrix_p, v, &x_2, &y_2);
+
+  /* Consider that the modelview matrix may flip the rectangle
+   * along the x or y axis... */
+#define SWAP(A,B) do { float tmp = B; B = A; A = tmp; } while (0)
+  if (x_1 > x_2)
+    SWAP (x_1, x_2);
+  if (y_1 > y_2)
+    SWAP (y_1, y_2);
+#undef SWAP
+
+  cogl_clip_push_window_rectangle (COGL_UTIL_NEARBYINT (x_1),
+                                   COGL_UTIL_NEARBYINT (y_1),
+                                   COGL_UTIL_NEARBYINT (x_2 - x_1),
+                                   COGL_UTIL_NEARBYINT (y_2 - y_1));
+  return TRUE;
+}
+
+void
+cogl_clip_push_rectangle (float x_1,
+                          float y_1,
+                          float x_2,
+                          float y_2)
+{
+  CoglHandle framebuffer;
+  CoglClipState *clip_state;
+  CoglClipStack *stack;
+  CoglMatrix modelview_matrix;
+
+  _COGL_GET_CONTEXT (ctx, NO_RETVAL);
+
+  /* We don't log clip stack changes in the journal so we must flush
+   * it before making modifications */
+  _cogl_journal_flush ();
+
+  /* Try and catch window space rectangles so we can redirect to
+   * cogl_clip_push_window_rect which will use scissoring. */
+  if (try_pushing_rect_as_window_rect (x_1, y_1, x_2, y_2))
+    return;
+
+  framebuffer = _cogl_get_framebuffer ();
+  clip_state = _cogl_framebuffer_get_clip_state (framebuffer);
+
+  stack = clip_state->stacks->data;
+
+  cogl_get_modelview_matrix (&modelview_matrix);
+
+  _cogl_clip_stack_push_rectangle (stack, x_1, y_1, x_2, y_2,
+                                   &modelview_matrix);
+
+  clip_state->stack_dirty = TRUE;
+}
+
+/* XXX: Deprecated API */
+void
+cogl_clip_push (float x_offset,
+                float y_offset,
+                float width,
+                float height)
+{
+  cogl_clip_push_rectangle (x_offset,
+                            y_offset,
+                            x_offset + width,
+                            y_offset + height);
+}
+
+void
+cogl_clip_push_from_path_preserve (void)
+{
+  CoglHandle framebuffer;
+  CoglClipState *clip_state;
+  CoglClipStack *stack;
+  CoglMatrix modelview_matrix;
+
+  _COGL_GET_CONTEXT (ctx, NO_RETVAL);
+
+  /* We don't log clip stack changes in the journal so we must flush
+   * it before making modifications */
+  _cogl_journal_flush ();
+
+  framebuffer = _cogl_get_framebuffer ();
+  clip_state = _cogl_framebuffer_get_clip_state (framebuffer);
+
+  stack = clip_state->stacks->data;
+
+  cogl_get_modelview_matrix (&modelview_matrix);
+
+  _cogl_clip_stack_push_from_path (stack, cogl_path_get (),
+                                   &modelview_matrix);
+
+  clip_state->stack_dirty = TRUE;
+}
+
+void
+cogl_clip_push_from_path (void)
+{
+  cogl_clip_push_from_path_preserve ();
+
+  cogl_path_new ();
+}
+
+static void
+_cogl_clip_pop_real (CoglClipState *clip_state)
+{
+  CoglClipStack *stack;
+
+  /* We don't log clip stack changes in the journal so we must flush
+   * it before making modifications */
+  _cogl_journal_flush ();
+
+  stack = clip_state->stacks->data;
+
+  _cogl_clip_stack_pop (stack);
+
+  clip_state->stack_dirty = TRUE;
+}
+
+void
+cogl_clip_pop (void)
+{
+  CoglHandle framebuffer;
+  CoglClipState *clip_state;
+
+  _COGL_GET_CONTEXT (ctx, NO_RETVAL);
+
+  framebuffer = _cogl_get_framebuffer ();
+  clip_state = _cogl_framebuffer_get_clip_state (framebuffer);
+
+  _cogl_clip_pop_real (clip_state);
+}
+
+void
+_cogl_clip_state_flush (CoglClipState *clip_state)
+{
+  CoglClipStack *stack;
+
+  if (!clip_state->stack_dirty)
+    return;
+
+  /* The current primitive journal does not support tracking changes to the
+   * clip stack...  */
+  _cogl_journal_flush ();
+
+  /* XXX: the handling of clipping is quite complex. It may involve use of
+   * the Cogl Journal or other Cogl APIs which may end up recursively
+   * wanting to ensure the clip state is flushed. We need to ensure we
+   * don't recurse infinitely...
+   */
+  clip_state->stack_dirty = FALSE;
+
+  stack = clip_state->stacks->data;
+
+  _cogl_clip_stack_flush (stack, &clip_state->stencil_used);
+}
+
+/* XXX: This should never have been made public API! */
+void
+cogl_clip_ensure (void)
+{
+  CoglClipState *clip_state;
+
+  clip_state = _cogl_framebuffer_get_clip_state (_cogl_get_framebuffer ());
+  _cogl_clip_state_flush (clip_state);
+}
+
+static void
+_cogl_clip_stack_save_real (CoglClipState *clip_state)
+{
+  CoglClipStack *stack;
+
+  /* We don't log clip stack changes in the journal so we must flush
+   * it before making modifications */
+  _cogl_journal_flush ();
+
+  stack = _cogl_clip_stack_new ();
+
+  clip_state->stacks = g_slist_prepend (clip_state->stacks, stack);
+  clip_state->stack_dirty = TRUE;
+}
+
+void
+cogl_clip_stack_save (void)
+{
+  CoglHandle framebuffer;
+  CoglClipState *clip_state;
+
+  _COGL_GET_CONTEXT (ctx, NO_RETVAL);
+
+  framebuffer = _cogl_get_framebuffer ();
+  clip_state = _cogl_framebuffer_get_clip_state (framebuffer);
+
+  _cogl_clip_stack_save_real (clip_state);
+}
+
+static void
+_cogl_clip_stack_restore_real (CoglClipState *clip_state)
+{
+  CoglClipStack *stack;
+
+  g_return_if_fail (clip_state->stacks != NULL);
+
+  /* We don't log clip stack changes in the journal so we must flush
+   * it before making modifications */
+  _cogl_journal_flush ();
+
+  stack = clip_state->stacks->data;
+
+  _cogl_clip_stack_free (stack);
+
+  /* Revert to an old stack */
+  clip_state->stacks = g_slist_delete_link (clip_state->stacks,
+                                            clip_state->stacks);
+
+  clip_state->stack_dirty = TRUE;
+}
+
+void
+cogl_clip_stack_restore (void)
+{
+  CoglHandle framebuffer;
+  CoglClipState *clip_state;
+
+  _COGL_GET_CONTEXT (ctx, NO_RETVAL);
+
+  framebuffer = _cogl_get_framebuffer ();
+  clip_state = _cogl_framebuffer_get_clip_state (framebuffer);
+
+  _cogl_clip_stack_restore_real (clip_state);
+}
+
+void
+_cogl_clip_state_init (CoglClipState *clip_state)
+{
+  _COGL_GET_CONTEXT (ctx, NO_RETVAL);
+
+  clip_state->stacks = NULL;
+  clip_state->stack_dirty = TRUE;
+
+  /* Add an intial stack */
+  _cogl_clip_stack_save_real (clip_state);
+}
+
+void
+_cogl_clip_state_destroy (CoglClipState *clip_state)
+{
+  /* Destroy all of the stacks */
+  while (clip_state->stacks)
+    _cogl_clip_stack_restore_real (clip_state);
+}
+
+void
+_cogl_clip_state_dirty (CoglClipState *clip_state)
+{
+  clip_state->stack_dirty = TRUE;
+}
diff --git a/clutter/cogl/cogl/cogl-clip-state.h b/clutter/cogl/cogl/cogl-clip-state.h
new file mode 100644 (file)
index 0000000..0f292dd
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * Cogl
+ *
+ * An object oriented GL/GLES Abstraction/Utility Layer
+ *
+ * Copyright (C) 2007,2008,2009,2010 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/>.
+ *
+ *
+ */
+
+#ifndef __COGL_CLIP_STATE_H
+#define __COGL_CLIP_STATE_H
+
+typedef struct _CoglClipState CoglClipState;
+
+struct _CoglClipState
+{
+  /* Stack of CoglClipStacks */
+  GSList *stacks;
+
+  gboolean stack_dirty;
+  gboolean stencil_used;
+};
+
+void
+_cogl_clip_state_init (CoglClipState *state);
+
+void
+_cogl_clip_state_destroy (CoglClipState *state);
+
+void
+_cogl_clip_state_dirty (CoglClipState *state);
+
+void
+_cogl_clip_state_flush (CoglClipState *clip_state);
+
+#endif /* __COGL_CLIP_STATE_H */
index d5d19a5..71edfa0 100644 (file)
@@ -26,7 +26,7 @@
 
 #include "cogl-handle.h"
 #include "cogl-matrix-stack.h"
-#include "cogl-clip-stack.h"
+#include "cogl-clip-state.h"
 
 typedef enum _CoglFramebufferType {
   COGL_FRAMEBUFFER_TYPE_ONSCREEN,
@@ -47,7 +47,7 @@ typedef struct
   int                 viewport_width;
   int                 viewport_height;
 
-  CoglClipStackState  clip_state;
+  CoglClipState       clip_state;
 } CoglFramebuffer;
 
 #define COGL_FRAMEBUFFER(X) ((CoglFramebuffer *)(X))
@@ -75,7 +75,7 @@ int
 _cogl_framebuffer_get_width (CoglHandle handle);
 int
 _cogl_framebuffer_get_height (CoglHandle handle);
-CoglClipStackState *
+CoglClipState *
 _cogl_framebuffer_get_clip_state (CoglHandle handle);
 void
 _cogl_framebuffer_set_viewport (CoglHandle handle,
index 3b00a85..082abf5 100644 (file)
@@ -131,13 +131,13 @@ _cogl_framebuffer_init (CoglFramebuffer *framebuffer,
   framebuffer->projection_stack = _cogl_matrix_stack_new ();
 
   /* Initialise the clip stack */
-  _cogl_clip_stack_state_init (&framebuffer->clip_state);
+  _cogl_clip_state_init (&framebuffer->clip_state);
 }
 
 void
 _cogl_framebuffer_free (CoglFramebuffer *framebuffer)
 {
-  _cogl_clip_stack_state_destroy (&framebuffer->clip_state);
+  _cogl_clip_state_destroy (&framebuffer->clip_state);
 
   _cogl_matrix_stack_destroy (framebuffer->modelview_stack);
   framebuffer->modelview_stack = NULL;
@@ -160,7 +160,7 @@ _cogl_framebuffer_get_height (CoglHandle handle)
   return framebuffer->height;
 }
 
-CoglClipStackState *
+CoglClipState *
 _cogl_framebuffer_get_clip_state (CoglHandle handle)
 {
   CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (handle);
@@ -551,7 +551,7 @@ _cogl_set_framebuffer_real (CoglFramebuffer *framebuffer)
    * we flush */
   _cogl_matrix_stack_dirty (framebuffer->modelview_stack);
   _cogl_matrix_stack_dirty (framebuffer->projection_stack);
-  _cogl_clip_stack_state_dirty (&framebuffer->clip_state);
+  _cogl_clip_state_dirty (&framebuffer->clip_state);
 }
 
 void
@@ -697,7 +697,7 @@ _cogl_framebuffer_flush_state (CoglHandle handle,
   /* XXX: Flushing clip state may trash the modelview and projection
    * matrices so we must do it before flushing the matrices...
    */
-  _cogl_flush_clip_state (&framebuffer->clip_state);
+  _cogl_clip_state_flush (&framebuffer->clip_state);
 
   if (!(flags & COGL_FRAMEBUFFER_FLUSH_SKIP_MODELVIEW))
     _cogl_matrix_stack_flush_to_gl (framebuffer->modelview_stack,
index 1a75558..2e1481d 100644 (file)
@@ -563,7 +563,7 @@ _cogl_path_fill_nodes (void)
       cogl_features_available (COGL_FEATURE_STENCIL_BUFFER))
     {
       CoglHandle framebuffer;
-      CoglClipStackState *clip_state;
+      CoglClipState *clip_state;
 
       _cogl_journal_flush ();
 
@@ -586,7 +586,7 @@ _cogl_path_fill_nodes (void)
        * we call cogl_flush() to emtpy the journal.
        */
       cogl_flush ();
-      _cogl_clip_stack_state_dirty (clip_state);
+      _cogl_clip_state_dirty (clip_state);
     }
   else
     {
index 60761af..ad2e64e 100644 (file)
@@ -1043,7 +1043,7 @@ cogl_set_projection_matrix (CoglMatrix *matrix)
   _COGL_MATRIX_DEBUG_PRINT (matrix);
 }
 
-CoglClipStackState *
+CoglClipState *
 _cogl_get_clip_state (void)
 {
   CoglHandle framebuffer;