mirror of
https://github.com/brl/mutter.git
synced 2025-06-26 23:17:04 +00:00
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:
@ -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;
|
||||
|
Reference in New Issue
Block a user