Bug 918 - Group doesn't clip if it's children are clipped
* clutter/cogl/common/cogl-clip-stack.h: * clutter/cogl/common/cogl-clip-stack.c: Added functions to maintain a stack of clipping rectangles. * clutter/cogl/gles/cogl.c: * clutter/cogl/gl/cogl.c: The cogl_clip_set and unset functions have moved into cogl-clip-stack.c which calls back to cogl.c to set the actual rectangles. Multiple clip rectangles are combined by merging the stencil buffers. * clutter/cogl/gles/cogl-primitives.c (_cogl_path_fill_nodes): * clutter/cogl/gl/cogl-primitives.c (_cogl_path_fill_nodes): Merge the stencil buffer with the contents of the clipping stack after drawing the path. * clutter/cogl/gles/cogl-context.h (CoglContext): * clutter/cogl/gl/cogl-context.h (CoglContext): Store the number of available stencil bits. * clutter/cogl/common/Makefile.am (libclutter_cogl_common_la_SOURCES): Added cogl-clip-stack.c
This commit is contained in:
parent
76b5a93afa
commit
7c69ca2997
@ -23,4 +23,5 @@ libclutter_cogl_common_la_SOURCES = \
|
||||
cogl-bitmap-fallback.c \
|
||||
cogl-primitives.c \
|
||||
cogl-primitives.h \
|
||||
cogl-bitmap-pixbuf.c
|
||||
cogl-bitmap-pixbuf.c \
|
||||
cogl-clip-stack.c
|
||||
|
180
common/cogl-clip-stack.c
Normal file
180
common/cogl-clip-stack.c
Normal file
@ -0,0 +1,180 @@
|
||||
/*
|
||||
* Clutter COGL
|
||||
*
|
||||
* A basic GL/GLES Abstraction/Utility Layer
|
||||
*
|
||||
* Authored By Matthew Allum <mallum@openedhand.com>
|
||||
*
|
||||
* Copyright (C) 2008 OpenedHand
|
||||
*
|
||||
* 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, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "cogl.h"
|
||||
#include "cogl-clip-stack.h"
|
||||
|
||||
/* These are defined in the particular backend (float in GL vs fixed
|
||||
in GL ES) */
|
||||
void _cogl_set_clip_planes (ClutterFixed x,
|
||||
ClutterFixed y,
|
||||
ClutterFixed width,
|
||||
ClutterFixed height);
|
||||
void _cogl_init_stencil_buffer (void);
|
||||
void _cogl_add_stencil_clip (ClutterFixed x,
|
||||
ClutterFixed y,
|
||||
ClutterFixed width,
|
||||
ClutterFixed height,
|
||||
gboolean first);
|
||||
void _cogl_disable_clip_planes (void);
|
||||
void _cogl_disable_stencil_buffer (void);
|
||||
void _cogl_set_matrix (const ClutterFixed *matrix);
|
||||
|
||||
typedef struct _CoglClipStackEntry CoglClipStackEntry;
|
||||
|
||||
struct _CoglClipStackEntry
|
||||
{
|
||||
/* The rectangle for this clip */
|
||||
ClutterFixed x_offset;
|
||||
ClutterFixed y_offset;
|
||||
ClutterFixed width;
|
||||
ClutterFixed height;
|
||||
|
||||
/* The matrix that was current when the clip was set */
|
||||
ClutterFixed matrix[16];
|
||||
};
|
||||
|
||||
static GList *cogl_clip_stack_top = NULL;
|
||||
static GList *cogl_clip_stack_bottom = NULL;
|
||||
static int cogl_clip_stack_depth = 0;
|
||||
|
||||
static void
|
||||
_cogl_clip_stack_add (const CoglClipStackEntry *entry, int depth)
|
||||
{
|
||||
int has_clip_planes = cogl_features_available (COGL_FEATURE_FOUR_CLIP_PLANES);
|
||||
|
||||
/* If this is the first entry and we support clip planes then use
|
||||
that instead */
|
||||
if (depth == 1 && has_clip_planes)
|
||||
_cogl_set_clip_planes (entry->x_offset,
|
||||
entry->y_offset,
|
||||
entry->width,
|
||||
entry->height);
|
||||
else
|
||||
_cogl_add_stencil_clip (entry->x_offset,
|
||||
entry->y_offset,
|
||||
entry->width,
|
||||
entry->height,
|
||||
depth == (has_clip_planes ? 2 : 1));
|
||||
}
|
||||
|
||||
void
|
||||
cogl_clip_set (ClutterFixed x_offset,
|
||||
ClutterFixed y_offset,
|
||||
ClutterFixed width,
|
||||
ClutterFixed height)
|
||||
{
|
||||
CoglClipStackEntry *entry = g_slice_new (CoglClipStackEntry);
|
||||
|
||||
/* Make a new entry */
|
||||
entry->x_offset = x_offset;
|
||||
entry->y_offset = y_offset;
|
||||
entry->width = width;
|
||||
entry->height = height;
|
||||
|
||||
cogl_get_modelview_matrix (entry->matrix);
|
||||
|
||||
/* Add the entry to the current clip */
|
||||
_cogl_clip_stack_add (entry, ++cogl_clip_stack_depth);
|
||||
|
||||
/* Store it in the stack */
|
||||
cogl_clip_stack_top = g_list_prepend (cogl_clip_stack_top, entry);
|
||||
if (cogl_clip_stack_bottom == NULL)
|
||||
cogl_clip_stack_bottom = cogl_clip_stack_top;
|
||||
}
|
||||
|
||||
void
|
||||
cogl_clip_unset (void)
|
||||
{
|
||||
g_return_if_fail (cogl_clip_stack_top != NULL);
|
||||
|
||||
/* Remove the top entry from the stack */
|
||||
g_slice_free (CoglClipStackEntry, cogl_clip_stack_top->data);
|
||||
cogl_clip_stack_top = g_list_delete_link (cogl_clip_stack_top,
|
||||
cogl_clip_stack_top);
|
||||
if (cogl_clip_stack_top == NULL)
|
||||
cogl_clip_stack_bottom = NULL;
|
||||
cogl_clip_stack_depth--;
|
||||
|
||||
/* Rebuild the clip */
|
||||
_cogl_clip_stack_rebuild (FALSE);
|
||||
}
|
||||
|
||||
void
|
||||
_cogl_clip_stack_rebuild (gboolean just_stencil)
|
||||
{
|
||||
int has_clip_planes = cogl_features_available (COGL_FEATURE_FOUR_CLIP_PLANES);
|
||||
GList *node;
|
||||
int depth = 1;
|
||||
|
||||
/* Disable clip planes if the stack is empty */
|
||||
if (has_clip_planes && cogl_clip_stack_depth < 1)
|
||||
_cogl_disable_clip_planes ();
|
||||
|
||||
/* Disable the stencil buffer if there isn't enough entries */
|
||||
if (cogl_clip_stack_depth < (has_clip_planes ? 2 : 1))
|
||||
_cogl_disable_stencil_buffer ();
|
||||
|
||||
/* Re-add every entry from the bottom of the stack up */
|
||||
for (node = cogl_clip_stack_bottom; node; node = node->prev, depth++)
|
||||
if (!just_stencil || !has_clip_planes || depth > 1)
|
||||
{
|
||||
const CoglClipStackEntry *entry = (CoglClipStackEntry *) node->data;
|
||||
cogl_push_matrix ();
|
||||
_cogl_set_matrix (entry->matrix);
|
||||
_cogl_clip_stack_add (entry, depth);
|
||||
cogl_pop_matrix ();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
_cogl_clip_stack_merge (void)
|
||||
{
|
||||
GList *node = cogl_clip_stack_bottom;
|
||||
|
||||
/* Merge the current clip stack on top of whatever is in the stencil
|
||||
buffer */
|
||||
if (node)
|
||||
{
|
||||
/* Skip the first entry if we have clipping planes */
|
||||
if (cogl_features_available (COGL_FEATURE_FOUR_CLIP_PLANES))
|
||||
node = node->prev;
|
||||
|
||||
while (node)
|
||||
{
|
||||
const CoglClipStackEntry *entry = (CoglClipStackEntry *) node->data;
|
||||
cogl_push_matrix ();
|
||||
_cogl_set_matrix (entry->matrix);
|
||||
_cogl_clip_stack_add (entry, 3);
|
||||
cogl_pop_matrix ();
|
||||
|
||||
node = node->prev;
|
||||
}
|
||||
}
|
||||
}
|
37
common/cogl-clip-stack.h
Normal file
37
common/cogl-clip-stack.h
Normal file
@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Clutter COGL
|
||||
*
|
||||
* A basic GL/GLES Abstraction/Utility Layer
|
||||
*
|
||||
* Authored By Matthew Allum <mallum@openedhand.com>
|
||||
*
|
||||
* Copyright (C) 2008 OpenedHand
|
||||
*
|
||||
* 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, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef __COGL_CLIP_STACK_H
|
||||
#define __COGL_CLIP_STACK_H
|
||||
|
||||
void cogl_clip_set (ClutterFixed x_offset,
|
||||
ClutterFixed y_offset,
|
||||
ClutterFixed width,
|
||||
ClutterFixed height);
|
||||
void cogl_clip_unset (void);
|
||||
void _cogl_clip_stack_rebuild (gboolean just_stencil);
|
||||
void _cogl_clip_stack_merge (void);
|
||||
|
||||
#endif /* __COGL_CLIP_STACK_H */
|
@ -33,6 +33,7 @@ typedef struct
|
||||
/* Features cache */
|
||||
CoglFeatureFlags feature_flags;
|
||||
gboolean features_cached;
|
||||
GLint num_stencil_bits;
|
||||
|
||||
/* Enable cache */
|
||||
gulong enable_flags;
|
||||
|
@ -30,6 +30,7 @@
|
||||
#include "cogl.h"
|
||||
#include "cogl-internal.h"
|
||||
#include "cogl-context.h"
|
||||
#include "cogl-clip-stack.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <gmodule.h>
|
||||
@ -145,9 +146,10 @@ _cogl_path_fill_nodes ()
|
||||
GE( glClear (GL_STENCIL_BUFFER_BIT) );
|
||||
|
||||
GE( glEnable (GL_STENCIL_TEST) );
|
||||
GE( glStencilFunc (GL_ALWAYS, 0x0, 0x0) );
|
||||
GE( glStencilFunc (GL_NEVER, 0x0, 0x1) );
|
||||
GE( glStencilOp (GL_INVERT, GL_INVERT, GL_INVERT) );
|
||||
GE( glColorMask (GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE) );
|
||||
|
||||
GE( glStencilMask (1) );
|
||||
|
||||
cogl_enable (COGL_ENABLE_VERTEX_ARRAY
|
||||
| (ctx->color_alpha < 255 ? COGL_ENABLE_BLEND : 0));
|
||||
@ -155,10 +157,14 @@ _cogl_path_fill_nodes ()
|
||||
GE( glVertexPointer (2, GL_FLOAT, 0, ctx->path_nodes) );
|
||||
GE( glDrawArrays (GL_TRIANGLE_FAN, 0, ctx->path_nodes_size) );
|
||||
|
||||
GE( glStencilFunc (GL_EQUAL, 0x1, 0x1) );
|
||||
GE( glStencilOp (GL_ZERO, GL_ZERO, GL_ZERO) );
|
||||
GE( glColorMask (GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE) );
|
||||
GE( glStencilMask (~(GLuint) 0) );
|
||||
|
||||
/* Merge the stencil buffer with any clipping rectangles */
|
||||
_cogl_clip_stack_merge ();
|
||||
|
||||
GE( glStencilFunc (GL_EQUAL, 0x1, 0x1) );
|
||||
GE( glStencilOp (GL_KEEP, GL_KEEP, GL_KEEP) );
|
||||
|
||||
bounds_x = CLUTTER_FIXED_FLOOR (ctx->path_nodes_min.x);
|
||||
bounds_y = CLUTTER_FIXED_FLOOR (ctx->path_nodes_min.y);
|
||||
bounds_w = CLUTTER_FIXED_CEIL (ctx->path_nodes_max.x - ctx->path_nodes_min.x);
|
||||
@ -166,5 +172,6 @@ _cogl_path_fill_nodes ()
|
||||
|
||||
cogl_rectangle (bounds_x, bounds_y, bounds_w, bounds_h);
|
||||
|
||||
GE( glDisable (GL_STENCIL_TEST) );
|
||||
/* Rebuild the stencil clip */
|
||||
_cogl_clip_stack_rebuild (TRUE);
|
||||
}
|
||||
|
338
gl/cogl.c
338
gl/cogl.c
@ -32,6 +32,7 @@
|
||||
#include <string.h>
|
||||
#include <gmodule.h>
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifdef HAVE_CLUTTER_GLX
|
||||
#include <dlfcn.h>
|
||||
@ -44,7 +45,6 @@ typedef CoglFuncPtr (*GLXGetProcAddressProc) (const guint8 *procName);
|
||||
#include "cogl-util.h"
|
||||
#include "cogl-context.h"
|
||||
|
||||
|
||||
/* GL error to string conversion */
|
||||
#if COGL_DEBUG
|
||||
struct token_string
|
||||
@ -447,94 +447,280 @@ set_clip_plane (GLint plane_num,
|
||||
}
|
||||
|
||||
void
|
||||
cogl_clip_set (ClutterFixed x_offset,
|
||||
ClutterFixed y_offset,
|
||||
ClutterFixed width,
|
||||
ClutterFixed height)
|
||||
_cogl_set_clip_planes (ClutterFixed x_offset,
|
||||
ClutterFixed y_offset,
|
||||
ClutterFixed width,
|
||||
ClutterFixed height)
|
||||
{
|
||||
if (cogl_features_available (COGL_FEATURE_FOUR_CLIP_PLANES))
|
||||
GLfloat modelview[16], projection[16];
|
||||
|
||||
GLfloat vertex_tl[4] = { CLUTTER_FIXED_TO_FLOAT (x_offset),
|
||||
CLUTTER_FIXED_TO_FLOAT (y_offset),
|
||||
0.0f, 1.0f };
|
||||
GLfloat vertex_tr[4] = { CLUTTER_FIXED_TO_FLOAT (x_offset + width),
|
||||
CLUTTER_FIXED_TO_FLOAT (y_offset),
|
||||
0.0f, 1.0f };
|
||||
GLfloat vertex_bl[4] = { CLUTTER_FIXED_TO_FLOAT (x_offset),
|
||||
CLUTTER_FIXED_TO_FLOAT (y_offset + height),
|
||||
0.0f, 1.0f };
|
||||
GLfloat vertex_br[4] = { CLUTTER_FIXED_TO_FLOAT (x_offset + width),
|
||||
CLUTTER_FIXED_TO_FLOAT (y_offset + height),
|
||||
0.0f, 1.0f };
|
||||
|
||||
GE( glGetFloatv (GL_MODELVIEW_MATRIX, modelview) );
|
||||
GE( glGetFloatv (GL_PROJECTION_MATRIX, projection) );
|
||||
|
||||
project_vertex (modelview, projection, vertex_tl);
|
||||
project_vertex (modelview, projection, vertex_tr);
|
||||
project_vertex (modelview, projection, vertex_bl);
|
||||
project_vertex (modelview, projection, vertex_br);
|
||||
|
||||
/* If the order of the top and bottom lines is different from the
|
||||
order of the left and right lines then the clip rect must have
|
||||
been transformed so that the back is visible. We therefore need
|
||||
to swap one pair of vertices otherwise all of the planes will be
|
||||
the wrong way around */
|
||||
if ((vertex_tl[0] < vertex_tr[0] ? 1 : 0)
|
||||
!= (vertex_bl[1] < vertex_tl[1] ? 1 : 0))
|
||||
{
|
||||
GLfloat modelview[16], projection[16];
|
||||
|
||||
GLfloat vertex_tl[4] = { CLUTTER_FIXED_TO_FLOAT (x_offset),
|
||||
CLUTTER_FIXED_TO_FLOAT (y_offset),
|
||||
0.0f, 1.0f };
|
||||
GLfloat vertex_tr[4] = { CLUTTER_FIXED_TO_FLOAT (x_offset + width),
|
||||
CLUTTER_FIXED_TO_FLOAT (y_offset),
|
||||
0.0f, 1.0f };
|
||||
GLfloat vertex_bl[4] = { CLUTTER_FIXED_TO_FLOAT (x_offset),
|
||||
CLUTTER_FIXED_TO_FLOAT (y_offset + height),
|
||||
0.0f, 1.0f };
|
||||
GLfloat vertex_br[4] = { CLUTTER_FIXED_TO_FLOAT (x_offset + width),
|
||||
CLUTTER_FIXED_TO_FLOAT (y_offset + height),
|
||||
0.0f, 1.0f };
|
||||
|
||||
GE( glGetFloatv (GL_MODELVIEW_MATRIX, modelview) );
|
||||
GE( glGetFloatv (GL_PROJECTION_MATRIX, projection) );
|
||||
|
||||
project_vertex (modelview, projection, vertex_tl);
|
||||
project_vertex (modelview, projection, vertex_tr);
|
||||
project_vertex (modelview, projection, vertex_bl);
|
||||
project_vertex (modelview, projection, vertex_br);
|
||||
|
||||
/* If the order of the top and bottom lines is different from
|
||||
the order of the left and right lines then the clip rect must
|
||||
have been transformed so that the back is visible. We
|
||||
therefore need to swap one pair of vertices otherwise all of
|
||||
the planes will be the wrong way around */
|
||||
if ((vertex_tl[0] < vertex_tr[0] ? 1 : 0)
|
||||
!= (vertex_bl[1] < vertex_tl[1] ? 1 : 0))
|
||||
{
|
||||
GLfloat temp[4];
|
||||
memcpy (temp, vertex_tl, sizeof (temp));
|
||||
memcpy (vertex_tl, vertex_tr, sizeof (temp));
|
||||
memcpy (vertex_tr, temp, sizeof (temp));
|
||||
memcpy (temp, vertex_bl, sizeof (temp));
|
||||
memcpy (vertex_bl, vertex_br, sizeof (temp));
|
||||
memcpy (vertex_br, temp, sizeof (temp));
|
||||
}
|
||||
|
||||
set_clip_plane (GL_CLIP_PLANE0, vertex_tl, vertex_tr);
|
||||
set_clip_plane (GL_CLIP_PLANE1, vertex_tr, vertex_br);
|
||||
set_clip_plane (GL_CLIP_PLANE2, vertex_br, vertex_bl);
|
||||
set_clip_plane (GL_CLIP_PLANE3, vertex_bl, vertex_tl);
|
||||
GLfloat temp[4];
|
||||
memcpy (temp, vertex_tl, sizeof (temp));
|
||||
memcpy (vertex_tl, vertex_tr, sizeof (temp));
|
||||
memcpy (vertex_tr, temp, sizeof (temp));
|
||||
memcpy (temp, vertex_bl, sizeof (temp));
|
||||
memcpy (vertex_bl, vertex_br, sizeof (temp));
|
||||
memcpy (vertex_br, temp, sizeof (temp));
|
||||
}
|
||||
else if (cogl_features_available (COGL_FEATURE_STENCIL_BUFFER))
|
||||
{
|
||||
GE( glEnable (GL_STENCIL_TEST) );
|
||||
|
||||
GE( glClearStencil (0.0f) );
|
||||
GE( glClear (GL_STENCIL_BUFFER_BIT) );
|
||||
set_clip_plane (GL_CLIP_PLANE0, vertex_tl, vertex_tr);
|
||||
set_clip_plane (GL_CLIP_PLANE1, vertex_tr, vertex_br);
|
||||
set_clip_plane (GL_CLIP_PLANE2, vertex_br, vertex_bl);
|
||||
set_clip_plane (GL_CLIP_PLANE3, vertex_bl, vertex_tl);
|
||||
}
|
||||
|
||||
GE( glStencilFunc (GL_NEVER, 0x1, 0x1) );
|
||||
GE( glStencilOp (GL_INCR, GL_INCR, GL_INCR) );
|
||||
|
||||
GE( glColor3f (1.0f, 1.0f, 1.0f) );
|
||||
|
||||
GE( glRectf (CLUTTER_FIXED_TO_FLOAT (x_offset),
|
||||
CLUTTER_FIXED_TO_FLOAT (y_offset),
|
||||
CLUTTER_FIXED_TO_FLOAT (x_offset + width),
|
||||
CLUTTER_FIXED_TO_FLOAT (y_offset + height)) );
|
||||
|
||||
GE( glStencilFunc (GL_EQUAL, 0x1, 0x1) );
|
||||
GE( glStencilOp (GL_KEEP, GL_KEEP, GL_KEEP) );
|
||||
}
|
||||
static int
|
||||
compare_y_coordinate (const void *a, const void *b)
|
||||
{
|
||||
GLfloat ay = ((const GLfloat *) a)[1];
|
||||
GLfloat by = ((const GLfloat *) b)[1];
|
||||
|
||||
return ay < by ? -1 : ay > by ? 1 : 0;
|
||||
}
|
||||
|
||||
void
|
||||
cogl_clip_unset (void)
|
||||
_cogl_add_stencil_clip (ClutterFixed x_offset,
|
||||
ClutterFixed y_offset,
|
||||
ClutterFixed width,
|
||||
ClutterFixed height,
|
||||
gboolean first)
|
||||
{
|
||||
if (cogl_features_available (COGL_FEATURE_FOUR_CLIP_PLANES))
|
||||
gboolean has_clip_planes
|
||||
= cogl_features_available (COGL_FEATURE_FOUR_CLIP_PLANES);
|
||||
|
||||
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
|
||||
|
||||
if (has_clip_planes)
|
||||
{
|
||||
GE( glDisable (GL_CLIP_PLANE3) );
|
||||
GE( glDisable (GL_CLIP_PLANE2) );
|
||||
GE( glDisable (GL_CLIP_PLANE1) );
|
||||
GE( glDisable (GL_CLIP_PLANE0) );
|
||||
}
|
||||
else if (cogl_features_available (COGL_FEATURE_STENCIL_BUFFER))
|
||||
|
||||
if (first)
|
||||
{
|
||||
GE( glDisable (GL_STENCIL_TEST) );
|
||||
GE( glEnable (GL_STENCIL_TEST) );
|
||||
|
||||
/* Initially disallow everything */
|
||||
GE( glClearStencil (0) );
|
||||
GE( glClear (GL_STENCIL_BUFFER_BIT) );
|
||||
|
||||
/* Punch out a hole to allow the rectangle */
|
||||
GE( glStencilFunc (GL_NEVER, 0x1, 0x1) );
|
||||
GE( glStencilOp (GL_REPLACE, GL_REPLACE, GL_REPLACE) );
|
||||
GE( glRectf (CLUTTER_FIXED_TO_FLOAT (x_offset),
|
||||
CLUTTER_FIXED_TO_FLOAT (y_offset),
|
||||
CLUTTER_FIXED_TO_FLOAT (x_offset + width),
|
||||
CLUTTER_FIXED_TO_FLOAT (y_offset + height)) );
|
||||
}
|
||||
else if (ctx->num_stencil_bits > 1)
|
||||
{
|
||||
/* Add one to every pixel of the stencil buffer in the
|
||||
rectangle */
|
||||
GE( glStencilFunc (GL_NEVER, 0x1, 0x3) );
|
||||
GE( glStencilOp (GL_INCR, GL_INCR, GL_INCR) );
|
||||
GE( glRectf (CLUTTER_FIXED_TO_FLOAT (x_offset),
|
||||
CLUTTER_FIXED_TO_FLOAT (y_offset),
|
||||
CLUTTER_FIXED_TO_FLOAT (x_offset + width),
|
||||
CLUTTER_FIXED_TO_FLOAT (y_offset + height)) );
|
||||
|
||||
/* 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( glStencilOp (GL_DECR, GL_DECR, GL_DECR) );
|
||||
GE( glPushMatrix () );
|
||||
GE( glLoadIdentity () );
|
||||
GE( glMatrixMode (GL_PROJECTION) );
|
||||
GE( glPushMatrix () );
|
||||
GE( glLoadIdentity () );
|
||||
GE( glRecti (-1, 1, 1, -1) );
|
||||
GE( glPopMatrix () );
|
||||
GE( glMatrixMode (GL_MODELVIEW) );
|
||||
GE( glPopMatrix () );
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Slower fallback if there is exactly one stencil bit. This
|
||||
tries to draw enough triangles to tessalate around the
|
||||
rectangle so that it can subtract from the stencil buffer for
|
||||
every pixel in the screen except those in the rectangle */
|
||||
GLfloat modelview[16], projection[16];
|
||||
GLfloat temp_point[4];
|
||||
GLfloat left_edge, right_edge, bottom_edge, top_edge;
|
||||
int i;
|
||||
GLfloat points[16] =
|
||||
{
|
||||
CLUTTER_FIXED_TO_FLOAT (x_offset),
|
||||
CLUTTER_FIXED_TO_FLOAT (y_offset),
|
||||
0, 1,
|
||||
CLUTTER_FIXED_TO_FLOAT (x_offset + width),
|
||||
CLUTTER_FIXED_TO_FLOAT (y_offset),
|
||||
0, 1,
|
||||
CLUTTER_FIXED_TO_FLOAT (x_offset),
|
||||
CLUTTER_FIXED_TO_FLOAT (y_offset + height),
|
||||
0, 1,
|
||||
CLUTTER_FIXED_TO_FLOAT (x_offset + width),
|
||||
CLUTTER_FIXED_TO_FLOAT (y_offset + height),
|
||||
0, 1
|
||||
};
|
||||
|
||||
GE( glGetFloatv (GL_MODELVIEW_MATRIX, modelview) );
|
||||
GE( glGetFloatv (GL_PROJECTION_MATRIX, projection) );
|
||||
|
||||
/* Project all of the vertices into screen coordinates */
|
||||
for (i = 0; i < 4; i++)
|
||||
project_vertex (modelview, projection, points + i * 4);
|
||||
|
||||
/* Sort the points by y coordinate */
|
||||
qsort (points, 4, sizeof (GLfloat) * 4, compare_y_coordinate);
|
||||
|
||||
/* Put the bottom two pairs and the top two pairs in
|
||||
left-right order */
|
||||
if (points[0] > points[4])
|
||||
{
|
||||
memcpy (temp_point, points, sizeof (GLfloat) * 4);
|
||||
memcpy (points, points + 4, sizeof (GLfloat) * 4);
|
||||
memcpy (points + 4, temp_point, sizeof (GLfloat) * 4);
|
||||
}
|
||||
if (points[8] > points[12])
|
||||
{
|
||||
memcpy (temp_point, points + 8, sizeof (GLfloat) * 4);
|
||||
memcpy (points + 8, points + 12, sizeof (GLfloat) * 4);
|
||||
memcpy (points + 12, temp_point, sizeof (GLfloat) * 4);
|
||||
}
|
||||
|
||||
/* If the clip rect goes outside of the screen then use the
|
||||
extents of the rect instead */
|
||||
left_edge = MIN (-1.0f, MIN (points[0], points[8]));
|
||||
right_edge = MAX ( 1.0f, MAX (points[4], points[12]));
|
||||
bottom_edge = MIN (-1.0f, MIN (points[1], points[5]));
|
||||
top_edge = MAX ( 1.0f, MAX (points[9], points[13]));
|
||||
|
||||
/* Using the identity matrix for the projection and
|
||||
modelview matrix, draw the triangles around the inner
|
||||
rectangle */
|
||||
GE( glStencilFunc (GL_NEVER, 0x1, 0x1) );
|
||||
GE( glStencilOp (GL_ZERO, GL_ZERO, GL_ZERO) );
|
||||
GE( glPushMatrix () );
|
||||
GE( glLoadIdentity () );
|
||||
GE( glMatrixMode (GL_PROJECTION) );
|
||||
GE( glPushMatrix () );
|
||||
GE( glLoadIdentity () );
|
||||
|
||||
/* Clear the left side */
|
||||
glBegin (GL_TRIANGLE_STRIP);
|
||||
glVertex2f (left_edge, bottom_edge);
|
||||
glVertex2fv (points);
|
||||
glVertex2f (left_edge, points[1]);
|
||||
glVertex2fv (points + 8);
|
||||
glVertex2f (left_edge, points[9]);
|
||||
glVertex2f (left_edge, top_edge);
|
||||
glEnd ();
|
||||
|
||||
/* Clear the right side */
|
||||
glBegin (GL_TRIANGLE_STRIP);
|
||||
glVertex2f (right_edge, top_edge);
|
||||
glVertex2fv (points + 12);
|
||||
glVertex2f (right_edge, points[13]);
|
||||
glVertex2fv (points + 4);
|
||||
glVertex2f (right_edge, points[5]);
|
||||
glVertex2f (right_edge, bottom_edge);
|
||||
glEnd ();
|
||||
|
||||
/* Clear the top side */
|
||||
glBegin (GL_TRIANGLE_STRIP);
|
||||
glVertex2f (left_edge, top_edge);
|
||||
glVertex2fv (points + 8);
|
||||
glVertex2f (points[8], top_edge);
|
||||
glVertex2fv (points + 12);
|
||||
glVertex2f (points[12], top_edge);
|
||||
glVertex2f (right_edge, top_edge);
|
||||
glEnd ();
|
||||
|
||||
/* Clear the bottom side */
|
||||
glBegin (GL_TRIANGLE_STRIP);
|
||||
glVertex2f (left_edge, bottom_edge);
|
||||
glVertex2fv (points);
|
||||
glVertex2f (points[0], bottom_edge);
|
||||
glVertex2fv (points + 4);
|
||||
glVertex2f (points[4], bottom_edge);
|
||||
glVertex2f (right_edge, bottom_edge);
|
||||
glEnd ();
|
||||
|
||||
GE( glPopMatrix () );
|
||||
GE( glMatrixMode (GL_MODELVIEW) );
|
||||
GE( glPopMatrix () );
|
||||
}
|
||||
|
||||
if (has_clip_planes)
|
||||
{
|
||||
GE( glEnable (GL_CLIP_PLANE0) );
|
||||
GE( glEnable (GL_CLIP_PLANE1) );
|
||||
GE( glEnable (GL_CLIP_PLANE2) );
|
||||
GE( glEnable (GL_CLIP_PLANE3) );
|
||||
}
|
||||
|
||||
/* Restore the stencil mode */
|
||||
GE( glStencilFunc (GL_EQUAL, 0x1, 0x1) );
|
||||
GE( glStencilOp (GL_KEEP, GL_KEEP, GL_KEEP) );
|
||||
}
|
||||
|
||||
void
|
||||
_cogl_set_matrix (const ClutterFixed *matrix)
|
||||
{
|
||||
float float_matrix[16];
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 16; i++)
|
||||
float_matrix[i] = CLUTTER_FIXED_TO_FLOAT (matrix[i]);
|
||||
|
||||
GE( glLoadIdentity () );
|
||||
GE( glMultMatrixf (float_matrix) );
|
||||
}
|
||||
|
||||
void
|
||||
_cogl_disable_stencil_buffer (void)
|
||||
{
|
||||
GE( glDisable (GL_STENCIL_TEST) );
|
||||
}
|
||||
|
||||
void
|
||||
_cogl_disable_clip_planes (void)
|
||||
{
|
||||
GE( glDisable (GL_CLIP_PLANE3) );
|
||||
GE( glDisable (GL_CLIP_PLANE2) );
|
||||
GE( glDisable (GL_CLIP_PLANE1) );
|
||||
GE( glDisable (GL_CLIP_PLANE0) );
|
||||
}
|
||||
|
||||
void
|
||||
@ -660,7 +846,6 @@ _cogl_features_init ()
|
||||
ClutterFeatureFlags flags = 0;
|
||||
const gchar *gl_extensions;
|
||||
GLint max_clip_planes = 0;
|
||||
GLint stencil_bits = 0;
|
||||
|
||||
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
|
||||
|
||||
@ -819,14 +1004,15 @@ _cogl_features_init ()
|
||||
flags |= COGL_FEATURE_OFFSCREEN_MULTISAMPLE;
|
||||
}
|
||||
|
||||
GE( glGetIntegerv (GL_STENCIL_BITS, &stencil_bits) );
|
||||
if (stencil_bits > 0)
|
||||
ctx->num_stencil_bits = 0;
|
||||
GE( glGetIntegerv (GL_STENCIL_BITS, &ctx->num_stencil_bits) );
|
||||
if (ctx->num_stencil_bits > 0)
|
||||
flags |= COGL_FEATURE_STENCIL_BUFFER;
|
||||
|
||||
GE( glGetIntegerv (GL_MAX_CLIP_PLANES, &max_clip_planes) );
|
||||
if (max_clip_planes >= 4)
|
||||
flags |= COGL_FEATURE_FOUR_CLIP_PLANES;
|
||||
|
||||
|
||||
/* Cache features */
|
||||
ctx->feature_flags = flags;
|
||||
ctx->features_cached = TRUE;
|
||||
|
@ -42,6 +42,7 @@ typedef struct
|
||||
/* Features cache */
|
||||
CoglFeatureFlags feature_flags;
|
||||
gboolean features_cached;
|
||||
GLint num_stencil_bits;
|
||||
|
||||
/* Enable cache */
|
||||
gulong enable_flags;
|
||||
|
@ -30,6 +30,7 @@
|
||||
#include "cogl.h"
|
||||
#include "cogl-internal.h"
|
||||
#include "cogl-context.h"
|
||||
#include "cogl-clip-stack.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <gmodule.h>
|
||||
@ -177,23 +178,29 @@ _cogl_path_fill_nodes ()
|
||||
GE( glClear (GL_STENCIL_BUFFER_BIT) );
|
||||
|
||||
GE( cogl_wrap_glEnable (GL_STENCIL_TEST) );
|
||||
GE( glStencilFunc (GL_ALWAYS, 0x0, 0x0) );
|
||||
GE( glStencilFunc (GL_NEVER, 0x0, 0x1) );
|
||||
GE( glStencilOp (GL_INVERT, GL_INVERT, GL_INVERT) );
|
||||
GE( glColorMask (GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE) );
|
||||
|
||||
GE( glStencilMask (1) );
|
||||
|
||||
cogl_enable (COGL_ENABLE_VERTEX_ARRAY
|
||||
| (ctx->color_alpha < 255 ? COGL_ENABLE_BLEND : 0));
|
||||
|
||||
GE( cogl_wrap_glVertexPointer (2, GL_FIXED, 0, ctx->path_nodes) );
|
||||
GE( cogl_wrap_glDrawArrays (GL_TRIANGLE_FAN, 0, ctx->path_nodes_size) );
|
||||
|
||||
GE( glStencilMask (~(GLuint) 0) );
|
||||
|
||||
/* Merge the stencil buffer with any clipping rectangles */
|
||||
_cogl_clip_stack_merge ();
|
||||
|
||||
GE( glStencilFunc (GL_EQUAL, 0x1, 0x1) );
|
||||
GE( glStencilOp (GL_ZERO, GL_ZERO, GL_ZERO) );
|
||||
GE( glColorMask (GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE) );
|
||||
GE( glStencilOp (GL_KEEP, GL_KEEP, GL_KEEP) );
|
||||
|
||||
cogl_rectangle (bounds_x, bounds_y, bounds_w, bounds_h);
|
||||
|
||||
GE( cogl_wrap_glDisable (GL_STENCIL_TEST) );
|
||||
/* Rebuild the stencil clip */
|
||||
_cogl_clip_stack_rebuild (TRUE);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
300
gles/cogl.c
300
gles/cogl.c
@ -30,6 +30,7 @@
|
||||
#include "cogl.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "cogl-internal.h"
|
||||
#include "cogl-util.h"
|
||||
@ -381,84 +382,257 @@ set_clip_plane (GLint plane_num,
|
||||
}
|
||||
|
||||
void
|
||||
cogl_clip_set (ClutterFixed x_offset,
|
||||
ClutterFixed y_offset,
|
||||
ClutterFixed width,
|
||||
ClutterFixed height)
|
||||
_cogl_set_clip_planes (ClutterFixed x_offset,
|
||||
ClutterFixed y_offset,
|
||||
ClutterFixed width,
|
||||
ClutterFixed height)
|
||||
{
|
||||
if (cogl_features_available (COGL_FEATURE_FOUR_CLIP_PLANES))
|
||||
GLfixed modelview[16], projection[16];
|
||||
|
||||
ClutterFixed vertex_tl[4] = { x_offset, y_offset, 0, CFX_ONE };
|
||||
ClutterFixed vertex_tr[4] = { x_offset + width, y_offset, 0, CFX_ONE };
|
||||
ClutterFixed vertex_bl[4] = { x_offset, y_offset + height, 0, CFX_ONE };
|
||||
ClutterFixed vertex_br[4] = { x_offset + width, y_offset + height,
|
||||
0, CFX_ONE };
|
||||
|
||||
GE( cogl_wrap_glGetFixedv (GL_MODELVIEW_MATRIX, modelview) );
|
||||
GE( cogl_wrap_glGetFixedv (GL_PROJECTION_MATRIX, projection) );
|
||||
|
||||
project_vertex (modelview, projection, vertex_tl);
|
||||
project_vertex (modelview, projection, vertex_tr);
|
||||
project_vertex (modelview, projection, vertex_bl);
|
||||
project_vertex (modelview, projection, vertex_br);
|
||||
|
||||
/* If the order of the top and bottom lines is different from
|
||||
the order of the left and right lines then the clip rect must
|
||||
have been transformed so that the back is visible. We
|
||||
therefore need to swap one pair of vertices otherwise all of
|
||||
the planes will be the wrong way around */
|
||||
if ((vertex_tl[0] < vertex_tr[0] ? 1 : 0)
|
||||
!= (vertex_bl[1] < vertex_tl[1] ? 1 : 0))
|
||||
{
|
||||
GLfixed modelview[16], projection[16];
|
||||
|
||||
ClutterFixed vertex_tl[4] = { x_offset, y_offset, 0, CFX_ONE };
|
||||
ClutterFixed vertex_tr[4] = { x_offset + width, y_offset, 0, CFX_ONE };
|
||||
ClutterFixed vertex_bl[4] = { x_offset, y_offset + height, 0, CFX_ONE };
|
||||
ClutterFixed vertex_br[4] = { x_offset + width, y_offset + height,
|
||||
0, CFX_ONE };
|
||||
|
||||
GE( cogl_wrap_glGetFixedv (GL_MODELVIEW_MATRIX, modelview) );
|
||||
GE( cogl_wrap_glGetFixedv (GL_PROJECTION_MATRIX, projection) );
|
||||
|
||||
project_vertex (modelview, projection, vertex_tl);
|
||||
project_vertex (modelview, projection, vertex_tr);
|
||||
project_vertex (modelview, projection, vertex_bl);
|
||||
project_vertex (modelview, projection, vertex_br);
|
||||
|
||||
/* If the order of the top and bottom lines is different from
|
||||
the order of the left and right lines then the clip rect must
|
||||
have been transformed so that the back is visible. We
|
||||
therefore need to swap one pair of vertices otherwise all of
|
||||
the planes will be the wrong way around */
|
||||
if ((vertex_tl[0] < vertex_tr[0] ? 1 : 0)
|
||||
!= (vertex_bl[1] < vertex_tl[1] ? 1 : 0))
|
||||
{
|
||||
ClutterFixed temp[4];
|
||||
memcpy (temp, vertex_tl, sizeof (temp));
|
||||
memcpy (vertex_tl, vertex_tr, sizeof (temp));
|
||||
memcpy (vertex_tr, temp, sizeof (temp));
|
||||
memcpy (temp, vertex_bl, sizeof (temp));
|
||||
memcpy (vertex_bl, vertex_br, sizeof (temp));
|
||||
memcpy (vertex_br, temp, sizeof (temp));
|
||||
}
|
||||
|
||||
set_clip_plane (GL_CLIP_PLANE0, vertex_tl, vertex_tr);
|
||||
set_clip_plane (GL_CLIP_PLANE1, vertex_tr, vertex_br);
|
||||
set_clip_plane (GL_CLIP_PLANE2, vertex_br, vertex_bl);
|
||||
set_clip_plane (GL_CLIP_PLANE3, vertex_bl, vertex_tl);
|
||||
ClutterFixed temp[4];
|
||||
memcpy (temp, vertex_tl, sizeof (temp));
|
||||
memcpy (vertex_tl, vertex_tr, sizeof (temp));
|
||||
memcpy (vertex_tr, temp, sizeof (temp));
|
||||
memcpy (temp, vertex_bl, sizeof (temp));
|
||||
memcpy (vertex_bl, vertex_br, sizeof (temp));
|
||||
memcpy (vertex_br, temp, sizeof (temp));
|
||||
}
|
||||
else if (cogl_features_available (COGL_FEATURE_STENCIL_BUFFER))
|
||||
{
|
||||
GE( cogl_wrap_glEnable (GL_STENCIL_TEST) );
|
||||
|
||||
GE( glClearStencil (0) );
|
||||
GE( glClear (GL_STENCIL_BUFFER_BIT) );
|
||||
set_clip_plane (GL_CLIP_PLANE0, vertex_tl, vertex_tr);
|
||||
set_clip_plane (GL_CLIP_PLANE1, vertex_tr, vertex_br);
|
||||
set_clip_plane (GL_CLIP_PLANE2, vertex_br, vertex_bl);
|
||||
set_clip_plane (GL_CLIP_PLANE3, vertex_bl, vertex_tl);
|
||||
}
|
||||
|
||||
GE( glStencilFunc (GL_NEVER, 0x1, 0x1) );
|
||||
GE( glStencilOp (GL_INCR, GL_INCR, GL_INCR) );
|
||||
static int
|
||||
compare_y_coordinate (const void *a, const void *b)
|
||||
{
|
||||
GLfixed ay = ((const GLfixed *) a)[1];
|
||||
GLfixed by = ((const GLfixed *) b)[1];
|
||||
|
||||
GE( cogl_wrap_glColor4x (CFX_ONE, CFX_ONE, CFX_ONE, CFX_ONE ) );
|
||||
|
||||
cogl_rectanglex (x_offset, y_offset, width, height);
|
||||
|
||||
GE( glStencilFunc (GL_EQUAL, 0x1, 0x1) );
|
||||
GE( glStencilOp (GL_KEEP, GL_KEEP, GL_KEEP) );
|
||||
}
|
||||
return ay < by ? -1 : ay > by ? 1 : 0;
|
||||
}
|
||||
|
||||
void
|
||||
cogl_clip_unset (void)
|
||||
_cogl_add_stencil_clip (ClutterFixed x_offset,
|
||||
ClutterFixed y_offset,
|
||||
ClutterFixed width,
|
||||
ClutterFixed height,
|
||||
gboolean first)
|
||||
{
|
||||
if (cogl_features_available (COGL_FEATURE_FOUR_CLIP_PLANES))
|
||||
gboolean has_clip_planes
|
||||
= cogl_features_available (COGL_FEATURE_FOUR_CLIP_PLANES);
|
||||
|
||||
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
|
||||
|
||||
if (has_clip_planes)
|
||||
{
|
||||
GE( cogl_wrap_glDisable (GL_CLIP_PLANE3) );
|
||||
GE( cogl_wrap_glDisable (GL_CLIP_PLANE2) );
|
||||
GE( cogl_wrap_glDisable (GL_CLIP_PLANE1) );
|
||||
GE( cogl_wrap_glDisable (GL_CLIP_PLANE0) );
|
||||
}
|
||||
else if (cogl_features_available (COGL_FEATURE_STENCIL_BUFFER))
|
||||
|
||||
if (first)
|
||||
{
|
||||
GE( cogl_wrap_glDisable (GL_STENCIL_TEST) );
|
||||
GE( cogl_wrap_glEnable (GL_STENCIL_TEST) );
|
||||
|
||||
/* Initially disallow everything */
|
||||
GE( glClearStencil (0) );
|
||||
GE( glClear (GL_STENCIL_BUFFER_BIT) );
|
||||
|
||||
/* Punch out a hole to allow the rectangle */
|
||||
GE( glStencilFunc (GL_NEVER, 0x1, 0x1) );
|
||||
GE( glStencilOp (GL_REPLACE, GL_REPLACE, GL_REPLACE) );
|
||||
|
||||
cogl_rectanglex (x_offset, y_offset, width, height);
|
||||
}
|
||||
else if (ctx->num_stencil_bits > 1)
|
||||
{
|
||||
/* Add one to every pixel of the stencil buffer in the
|
||||
rectangle */
|
||||
GE( glStencilFunc (GL_NEVER, 0x1, 0x3) );
|
||||
GE( glStencilOp (GL_INCR, GL_INCR, GL_INCR) );
|
||||
cogl_rectanglex (x_offset, y_offset, width, height);
|
||||
|
||||
/* 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( glStencilOp (GL_DECR, GL_DECR, GL_DECR) );
|
||||
GE( cogl_wrap_glPushMatrix () );
|
||||
GE( cogl_wrap_glLoadIdentity () );
|
||||
GE( cogl_wrap_glMatrixMode (GL_PROJECTION) );
|
||||
GE( cogl_wrap_glPushMatrix () );
|
||||
GE( cogl_wrap_glLoadIdentity () );
|
||||
cogl_rectanglex (-CFX_ONE, -CFX_ONE,
|
||||
CLUTTER_INT_TO_FIXED (2),
|
||||
CLUTTER_INT_TO_FIXED (2));
|
||||
GE( cogl_wrap_glPopMatrix () );
|
||||
GE( cogl_wrap_glMatrixMode (GL_MODELVIEW) );
|
||||
GE( cogl_wrap_glPopMatrix () );
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Slower fallback if there is exactly one stencil bit. This
|
||||
tries to draw enough triangles to tessalate around the
|
||||
rectangle so that it can subtract from the stencil buffer for
|
||||
every pixel in the screen except those in the rectangle */
|
||||
GLfixed modelview[16], projection[16];
|
||||
GLfixed temp_point[4];
|
||||
GLfixed left_edge, right_edge, bottom_edge, top_edge;
|
||||
int i;
|
||||
GLfixed points[16] =
|
||||
{
|
||||
x_offset, y_offset, 0, CFX_ONE,
|
||||
x_offset + width, y_offset, 0, CFX_ONE,
|
||||
x_offset, y_offset + height, 0, CFX_ONE,
|
||||
x_offset + width, y_offset + height, 0, CFX_ONE
|
||||
};
|
||||
GLfixed draw_points[12];
|
||||
|
||||
GE( cogl_wrap_glGetFixedv (GL_MODELVIEW_MATRIX, modelview) );
|
||||
GE( cogl_wrap_glGetFixedv (GL_PROJECTION_MATRIX, projection) );
|
||||
|
||||
/* Project all of the vertices into screen coordinates */
|
||||
for (i = 0; i < 4; i++)
|
||||
project_vertex (modelview, projection, points + i * 4);
|
||||
|
||||
/* Sort the points by y coordinate */
|
||||
qsort (points, 4, sizeof (GLfixed) * 4, compare_y_coordinate);
|
||||
|
||||
/* Put the bottom two pairs and the top two pairs in
|
||||
left-right order */
|
||||
if (points[0] > points[4])
|
||||
{
|
||||
memcpy (temp_point, points, sizeof (GLfixed) * 4);
|
||||
memcpy (points, points + 4, sizeof (GLfixed) * 4);
|
||||
memcpy (points + 4, temp_point, sizeof (GLfixed) * 4);
|
||||
}
|
||||
if (points[8] > points[12])
|
||||
{
|
||||
memcpy (temp_point, points + 8, sizeof (GLfixed) * 4);
|
||||
memcpy (points + 8, points + 12, sizeof (GLfixed) * 4);
|
||||
memcpy (points + 12, temp_point, sizeof (GLfixed) * 4);
|
||||
}
|
||||
|
||||
/* If the clip rect goes outside of the screen then use the
|
||||
extents of the rect instead */
|
||||
left_edge = MIN (-CFX_ONE, MIN (points[0], points[8]));
|
||||
right_edge = MAX ( CFX_ONE, MAX (points[4], points[12]));
|
||||
bottom_edge = MIN (-CFX_ONE, MIN (points[1], points[5]));
|
||||
top_edge = MAX ( CFX_ONE, MAX (points[9], points[13]));
|
||||
|
||||
/* Using the identity matrix for the projection and
|
||||
modelview matrix, draw the triangles around the inner
|
||||
rectangle */
|
||||
GE( glStencilFunc (GL_NEVER, 0x1, 0x1) );
|
||||
GE( glStencilOp (GL_ZERO, GL_ZERO, GL_ZERO) );
|
||||
GE( cogl_wrap_glPushMatrix () );
|
||||
GE( cogl_wrap_glLoadIdentity () );
|
||||
GE( cogl_wrap_glMatrixMode (GL_PROJECTION) );
|
||||
GE( cogl_wrap_glPushMatrix () );
|
||||
GE( cogl_wrap_glLoadIdentity () );
|
||||
|
||||
cogl_enable (COGL_ENABLE_VERTEX_ARRAY
|
||||
| (ctx->color_alpha < 255 ? COGL_ENABLE_BLEND : 0));
|
||||
GE( cogl_wrap_glVertexPointer (2, GL_FIXED, 0, draw_points) );
|
||||
|
||||
/* Clear the left side */
|
||||
draw_points[0] = left_edge; draw_points[1] = bottom_edge;
|
||||
draw_points[2] = points[0]; draw_points[3] = points[1];
|
||||
draw_points[4] = left_edge; draw_points[5] = points[1];
|
||||
draw_points[6] = points[8]; draw_points[7] = points[9];
|
||||
draw_points[8] = left_edge; draw_points[9] = points[9];
|
||||
draw_points[10] = left_edge; draw_points[11] = top_edge;
|
||||
GE( cogl_wrap_glDrawArrays (GL_TRIANGLE_STRIP, 0, 6) );
|
||||
|
||||
/* Clear the right side */
|
||||
draw_points[0] = right_edge; draw_points[1] = top_edge;
|
||||
draw_points[2] = points[12]; draw_points[3] = points[13];
|
||||
draw_points[4] = right_edge; draw_points[5] = points[13];
|
||||
draw_points[6] = points[4]; draw_points[7] = points[5];
|
||||
draw_points[8] = right_edge; draw_points[9] = points[5];
|
||||
draw_points[10] = right_edge; draw_points[11] = bottom_edge;
|
||||
GE( cogl_wrap_glDrawArrays (GL_TRIANGLE_STRIP, 0, 6) );
|
||||
|
||||
/* Clear the top side */
|
||||
draw_points[0] = left_edge; draw_points[1] = top_edge;
|
||||
draw_points[2] = points[8]; draw_points[3] = points[9];
|
||||
draw_points[4] = points[8]; draw_points[5] = top_edge;
|
||||
draw_points[6] = points[12]; draw_points[7] = points[13];
|
||||
draw_points[8] = points[12]; draw_points[9] = top_edge;
|
||||
draw_points[10] = right_edge; draw_points[11] = top_edge;
|
||||
GE( cogl_wrap_glDrawArrays (GL_TRIANGLE_STRIP, 0, 6) );
|
||||
|
||||
/* Clear the bottom side */
|
||||
draw_points[0] = left_edge; draw_points[1] = bottom_edge;
|
||||
draw_points[2] = points[0]; draw_points[3] = points[1];
|
||||
draw_points[4] = points[0]; draw_points[5] = bottom_edge;
|
||||
draw_points[6] = points[4]; draw_points[7] = points[5];
|
||||
draw_points[8] = points[4]; draw_points[9] = bottom_edge;
|
||||
draw_points[10] = right_edge; draw_points[11] = bottom_edge;
|
||||
GE( cogl_wrap_glDrawArrays (GL_TRIANGLE_STRIP, 0, 6) );
|
||||
|
||||
GE( cogl_wrap_glPopMatrix () );
|
||||
GE( cogl_wrap_glMatrixMode (GL_MODELVIEW) );
|
||||
GE( cogl_wrap_glPopMatrix () );
|
||||
}
|
||||
|
||||
if (has_clip_planes)
|
||||
{
|
||||
GE( cogl_wrap_glEnable (GL_CLIP_PLANE0) );
|
||||
GE( cogl_wrap_glEnable (GL_CLIP_PLANE1) );
|
||||
GE( cogl_wrap_glEnable (GL_CLIP_PLANE2) );
|
||||
GE( cogl_wrap_glEnable (GL_CLIP_PLANE3) );
|
||||
}
|
||||
|
||||
/* Restore the stencil mode */
|
||||
GE( glStencilFunc (GL_EQUAL, 0x1, 0x1) );
|
||||
GE( glStencilOp (GL_KEEP, GL_KEEP, GL_KEEP) );
|
||||
}
|
||||
|
||||
void
|
||||
_cogl_set_matrix (const ClutterFixed *matrix)
|
||||
{
|
||||
GE( cogl_wrap_glLoadIdentity () );
|
||||
GE( cogl_wrap_glMultMatrixx (matrix) );
|
||||
}
|
||||
|
||||
void
|
||||
_cogl_disable_stencil_buffer (void)
|
||||
{
|
||||
GE( cogl_wrap_glDisable (GL_STENCIL_TEST) );
|
||||
}
|
||||
|
||||
void
|
||||
_cogl_disable_clip_planes (void)
|
||||
{
|
||||
GE( cogl_wrap_glDisable (GL_CLIP_PLANE3) );
|
||||
GE( cogl_wrap_glDisable (GL_CLIP_PLANE2) );
|
||||
GE( cogl_wrap_glDisable (GL_CLIP_PLANE1) );
|
||||
GE( cogl_wrap_glDisable (GL_CLIP_PLANE0) );
|
||||
}
|
||||
|
||||
void
|
||||
@ -583,13 +757,13 @@ static void
|
||||
_cogl_features_init ()
|
||||
{
|
||||
ClutterFeatureFlags flags = 0;
|
||||
int stencil_bits = 0;
|
||||
int max_clip_planes = 0;
|
||||
|
||||
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
|
||||
|
||||
GE( cogl_wrap_glGetIntegerv (GL_STENCIL_BITS, &stencil_bits) );
|
||||
if (stencil_bits > 0)
|
||||
ctx->num_stencil_bits = 0;
|
||||
GE( cogl_wrap_glGetIntegerv (GL_STENCIL_BITS, &ctx->num_stencil_bits) );
|
||||
if (ctx->num_stencil_bits > 0)
|
||||
flags |= COGL_FEATURE_STENCIL_BUFFER;
|
||||
|
||||
GE( cogl_wrap_glGetIntegerv (GL_MAX_CLIP_PLANES, &max_clip_planes) );
|
||||
|
Loading…
Reference in New Issue
Block a user