[cogl] Adds cogl_read_pixels to replace direct use of glReadPixels

To allow for flushing of batched geometry within Cogl we can't support users
directly calling glReadPixels.  glReadPixels is also awkward, not least
because it returns upside down image data.

All the unit tests have been swithed over and clutter_stage_read_pixels now
sits on top of this too.
This commit is contained in:
Robert Bragg
2009-06-17 14:30:44 +01:00
parent 27fff12a6a
commit 24ca92951f
9 changed files with 151 additions and 66 deletions

View File

@ -1366,10 +1366,9 @@ clutter_stage_read_pixels (ClutterStage *stage,
gint height)
{
guchar *pixels;
guchar *temprow;
GLint viewport[4];
gint rowstride;
gint stage_x, stage_y, stage_width, stage_height;
gint stage_width, stage_height;
g_return_val_if_fail (CLUTTER_IS_STAGE (stage), NULL);
@ -1383,8 +1382,6 @@ clutter_stage_read_pixels (ClutterStage *stage,
clutter_actor_paint (CLUTTER_ACTOR (stage));
glGetIntegerv (GL_VIEWPORT, viewport);
stage_x = viewport[0];
stage_y = viewport[1];
stage_width = viewport[2];
stage_height = viewport[3];
@ -1397,42 +1394,11 @@ clutter_stage_read_pixels (ClutterStage *stage,
rowstride = width * 4;
pixels = g_malloc (height * rowstride);
temprow = g_malloc (rowstride);
/* Setup the pixel store parameters that may have been changed by
Cogl */
glPixelStorei (GL_PACK_ALIGNMENT, 4);
#ifdef HAVE_COGL_GL
glPixelStorei (GL_PACK_ROW_LENGTH, 0);
glPixelStorei (GL_PACK_SKIP_PIXELS, 0);
glPixelStorei (GL_PACK_SKIP_ROWS, 0);
#endif /* HAVE_COGL_GL */
/* The y co-ordinate should be given in OpenGL's coordinate system
so 0 is the bottom row */
y = stage_height - y - height;
glFinish ();
/* check whether we need to read into a smaller temporary buffer */
glReadPixels (x, y, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
/* vertically flip the buffer in-place */
for (y = 0; y < height / 2; y++)
{
if (y != height - y - 1) /* skip center row */
{
memcpy (temprow,
pixels + y * rowstride, rowstride);
memcpy (pixels + y * rowstride,
pixels + (height - y - 1) * rowstride, rowstride);
memcpy (pixels + (height - y - 1) * rowstride,
temprow,
rowstride);
}
}
g_free (temprow);
cogl_read_pixels (x, y, width, height,
COGL_READ_PIXELS_COLOR_BUFFER,
COGL_PIXEL_FORMAT_RGBA_8888,
pixels);
return pixels;
}

View File

@ -691,6 +691,39 @@ void cogl_push_draw_buffer (void);
*/
void cogl_pop_draw_buffer (void);
/**
* CoglReadPixelsFlags:
* @COGL_READ_PIXELS_COLOR_BUFFER: Read from the color buffer
*/
typedef enum _CoglReadPixelsFlags
{
COGL_READ_PIXELS_COLOR_BUFFER = 1L<<0
} CoglReadPixelsFlags;
/**
* cogl_read_pixels:
* @x: The window x position to start reading from
* @y: The window y position to start reading from
* @width: The width of the rectangle you want to read
* @height: The height of the rectangle you want to read
* @source: Identifies which auxillary buffer you want to read
* (only COGL_READ_PIXELS_COLOR_BUFFER supported currently)
* @format: The pixel format you want the result in
* (only COGL_PIXEL_FORMAT_RGBA_8888 supported currently)
* @pixels: The location to write the pixel data.
*
* This reads a rectangle of pixels from the current draw buffer where
* position (0, 0) is the top left. The pixel at (x, y) is the first
* read, and the data is returned with a rowstride of (width * 4)
*/
void cogl_read_pixels (int x,
int y,
int width,
int height,
CoglReadPixelsFlags source,
CoglPixelFormat format,
guint8 *pixels);
/*
* Internal API available only to Clutter.

View File

@ -572,6 +572,8 @@ void
cogl_get_viewport (float v[4])
{
/* FIXME: cogl_get_viewport should return a gint vec */
/* FIXME: cogl_get_viewport should only return a width + height
* (I don't think we need to support offset viewports) */
#if defined (HAVE_COGL_GLES2) || defined (HAVE_COGL_GLES)
GLint viewport[4];
int i;
@ -676,3 +678,57 @@ cogl_flush_gl_state (int flags)
}
#endif
void
cogl_read_pixels (int x,
int y,
int width,
int height,
CoglReadPixelsFlags source,
CoglPixelFormat format,
guint8 *pixels)
{
GLint viewport[4];
GLint viewport_height;
int rowstride = width * 4;
guint8 temprow[rowstride];
g_return_if_fail (format == COGL_PIXEL_FORMAT_RGBA_8888);
g_return_if_fail (source == COGL_READ_PIXELS_COLOR_BUFFER);
glGetIntegerv (GL_VIEWPORT, viewport);
viewport_height = viewport[3];
/* The y co-ordinate should be given in OpenGL's coordinate system
so 0 is the bottom row */
y = viewport_height - y - height;
/* Setup the pixel store parameters that may have been changed by
Cogl */
glPixelStorei (GL_PACK_ALIGNMENT, 4);
#ifdef HAVE_COGL_GL
glPixelStorei (GL_PACK_ROW_LENGTH, 0);
glPixelStorei (GL_PACK_SKIP_PIXELS, 0);
glPixelStorei (GL_PACK_SKIP_ROWS, 0);
#endif /* HAVE_COGL_GL */
glReadPixels (x, y, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
/* TODO: consider using the GL_MESA_pack_invert extension in the future
* to avoid this flip... */
/* vertically flip the buffer in-place */
for (y = 0; y < height / 2; y++)
{
if (y != height - y - 1) /* skip center row */
{
memcpy (temprow,
pixels + y * rowstride, rowstride);
memcpy (pixels + y * rowstride,
pixels + (height - y - 1) * rowstride, rowstride);
memcpy (pixels + (height - y - 1) * rowstride,
temprow,
rowstride);
}
}
}