From aded4218d843e4a379b94b8b2297d60078ad6f1a Mon Sep 17 00:00:00 2001 From: Sam Lantinga Date: Mon, 16 Nov 2009 07:13:07 +0000 Subject: [PATCH] You can specify the format for pixel data in SDL_RenderReadPixels() and SDL_RenderWritePixels() This code still doesn't quite work yet. :) --- include/SDL_video.h | 9 ++++-- src/video/SDL_renderer_gl.c | 54 ++++++++++++++++++++++++++++------ src/video/SDL_renderer_sw.c | 41 ++++++-------------------- src/video/SDL_sysvideo.h | 4 +-- src/video/SDL_video.c | 20 ++++++++++--- test/automated/common/common.h | 2 ++ test/automated/render/render.c | 2 +- 7 files changed, 82 insertions(+), 50 deletions(-) diff --git a/include/SDL_video.h b/include/SDL_video.h index 4ce7f9a4a..79e47f22f 100644 --- a/include/SDL_video.h +++ b/include/SDL_video.h @@ -1173,8 +1173,9 @@ extern DECLSPEC int SDLCALL SDL_RenderCopy(SDL_TextureID textureID, * * \param rect A pointer to the rectangle to read, or NULL for the entire * render target. - * \param pixels A pointer to be filled in with the pixel data in the rendering - * target format. + * \param format The desired format of the pixel data, or 0 to use the format + * of the rendering target + * \param pixels A pointer to be filled in with the pixel data * \param pitch The pitch of the pixels parameter. * * \return 0 on success, or -1 if pixel reading is not supported. @@ -1182,6 +1183,7 @@ extern DECLSPEC int SDLCALL SDL_RenderCopy(SDL_TextureID textureID, * \warning This is a very slow operation, and should not be used frequently. */ extern DECLSPEC int SDLCALL SDL_RenderReadPixels(const SDL_Rect * rect, + Uint32 format, void *pixels, int pitch); /** @@ -1189,6 +1191,8 @@ extern DECLSPEC int SDLCALL SDL_RenderReadPixels(const SDL_Rect * rect, * * \param rect A pointer to the rectangle to write, or NULL for the entire * render target. + * \param format The format of the pixel data, or 0 to use the format + * of the rendering target * \param pixels A pointer to the pixel data to write. * \param pitch The pitch of the pixels parameter. * @@ -1197,6 +1201,7 @@ extern DECLSPEC int SDLCALL SDL_RenderReadPixels(const SDL_Rect * rect, * \warning This is a very slow operation, and should not be used frequently. */ extern DECLSPEC int SDLCALL SDL_RenderWritePixels(const SDL_Rect * rect, + Uint32 format, const void *pixels, int pitch); diff --git a/src/video/SDL_renderer_gl.c b/src/video/SDL_renderer_gl.c index a002229f7..52657068b 100644 --- a/src/video/SDL_renderer_gl.c +++ b/src/video/SDL_renderer_gl.c @@ -103,9 +103,9 @@ static int GL_RenderFill(SDL_Renderer * renderer, const SDL_Rect * rect); static int GL_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture, const SDL_Rect * srcrect, const SDL_Rect * dstrect); static int GL_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect, - void * pixels, int pitch); + Uint32 pixel_format, void * pixels, int pitch); static int GL_RenderWritePixels(SDL_Renderer * renderer, const SDL_Rect * rect, - const void * pixels, int pitch); + Uint32 pixel_format, const void * pixels, int pitch); static void GL_RenderPresent(SDL_Renderer * renderer); static void GL_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture); static void GL_DestroyRenderer(SDL_Renderer * renderer); @@ -1254,16 +1254,16 @@ GL_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture, static int GL_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect, - void * pixels, int pitch) + Uint32 pixel_format, void * pixels, int pitch) { GL_RenderData *data = (GL_RenderData *) renderer->driverdata; - SDL_Window *window = SDL_GetWindowFromID(renderer->window); - SDL_VideoDisplay *display = SDL_GetDisplayFromWindow(window); - Uint32 pixel_format = display->current_mode.format; GLint internalFormat; GLenum format, type; + Uint8 *src, *dst, *tmp; + int length, rows; if (!convert_format(data, pixel_format, &internalFormat, &format, &type)) { + /* FIXME: Do a temp copy to a format that is supported */ SDL_SetError("Unsupported pixel format"); return -1; } @@ -1275,16 +1275,52 @@ GL_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect, } data->glPixelStorei(GL_PACK_ALIGNMENT, 1); data->glPixelStorei(GL_PACK_ROW_LENGTH, - -2 * (pitch / bytes_per_pixel(pixel_format))); + (pitch / bytes_per_pixel(pixel_format))); data->glReadPixels(rect->x, rect->y+rect->h-1, rect->w, rect->h, - format, type, pixels + (rect->h-1)*pitch); + format, type, pixels); + + /* Flip the rows to be top-down */ + length = rect->w * bytes_per_pixel(pixel_format); + src = (Uint8*)pixels + (rect->h-1)*pitch; + dst = (Uint8*)pixels; + tmp = SDL_stack_alloc(Uint8, length); + rows = rect->h / 2; + while (rows--) { + SDL_memcpy(tmp, dst, length); + SDL_memcpy(dst, src, length); + SDL_memcpy(src, tmp, length); + } + SDL_stack_free(tmp); } static int GL_RenderWritePixels(SDL_Renderer * renderer, const SDL_Rect * rect, - const void * pixels, int pitch) + Uint32 pixel_format, const void * pixels, int pitch) { + GL_RenderData *data = (GL_RenderData *) renderer->driverdata; + GLint internalFormat; + GLenum format, type; + + if (!convert_format(data, pixel_format, &internalFormat, &format, &type)) { + /* FIXME: Do a temp copy to a format that is supported */ + SDL_SetError("Unsupported pixel format"); + return -1; + } + + /* FIXME: We need to copy the data and flip it */ + + if (pixel_format == SDL_PIXELFORMAT_INDEX1LSB) { + data->glPixelStorei(GL_UNPACK_LSB_FIRST, 1); + } else if (pixel_format == SDL_PIXELFORMAT_INDEX1MSB) { + data->glPixelStorei(GL_UNPACK_LSB_FIRST, 0); + } + data->glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + data->glPixelStorei(GL_UNPACK_ROW_LENGTH, + (pitch / bytes_per_pixel(pixel_format))); + + data->glReadPixels(rect->x, rect->y+rect->h-1, rect->w, rect->h, + format, type, pixels); } static void diff --git a/src/video/SDL_renderer_sw.c b/src/video/SDL_renderer_sw.c index 1365645ad..e85e8f972 100644 --- a/src/video/SDL_renderer_sw.c +++ b/src/video/SDL_renderer_sw.c @@ -66,9 +66,9 @@ static int SW_RenderFill(SDL_Renderer * renderer, const SDL_Rect * rect); static int SW_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture, const SDL_Rect * srcrect, const SDL_Rect * dstrect); static int SW_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect, - void * pixels, int pitch); + Uint32 format, void * pixels, int pitch); static int SW_RenderWritePixels(SDL_Renderer * renderer, const SDL_Rect * rect, - const void * pixels, int pitch); + Uint32 format, const void * pixels, int pitch); static void SW_RenderPresent(SDL_Renderer * renderer); static void SW_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture); static void SW_DestroyRenderer(SDL_Renderer * renderer); @@ -736,12 +736,9 @@ SW_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture, static int SW_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect, - void * pixels, int pitch) + Uint32 format, void * pixels, int pitch) { SW_RenderData *data = (SW_RenderData *) renderer->driverdata; - const Uint8 *src; - Uint8 *dst; - int src_pitch, dst_pitch, w, h; if (data->renderer->LockTexture(data->renderer, data->texture[data->current_texture], @@ -750,17 +747,9 @@ SW_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect, return -1; } - src = data->surface.pixels; - src_pitch = data->surface.pitch; - dst = pixels; - dst_pitch = pitch; - h = rect->h; - w = rect->w * data->surface.format->BytesPerPixel; - while (h--) { - SDL_memcpy(dst, src, w); - src += src_pitch; - dst += dst_pitch; - } + SDL_ConvertPixels(rect->w, rect->h, + data->format, data->surface.pixels, data->surface.pitch, + format, pixels, pitch); data->renderer->UnlockTexture(data->renderer, data->texture[data->current_texture]); @@ -769,12 +758,9 @@ SW_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect, static int SW_RenderWritePixels(SDL_Renderer * renderer, const SDL_Rect * rect, - const void * pixels, int pitch) + Uint32 format, const void * pixels, int pitch) { SW_RenderData *data = (SW_RenderData *) renderer->driverdata; - const Uint8 *src; - Uint8 *dst; - int src_pitch, dst_pitch, w, h; if (data->renderer->info.flags & SDL_RENDERER_PRESENTCOPY) { SDL_AddDirtyRect(&data->dirty, rect); @@ -787,17 +773,8 @@ SW_RenderWritePixels(SDL_Renderer * renderer, const SDL_Rect * rect, return -1; } - src = pixels; - src_pitch = pitch; - dst = data->surface.pixels; - dst_pitch = data->surface.pitch; - h = rect->h; - w = rect->w * data->surface.format->BytesPerPixel; - while (h--) { - SDL_memcpy(dst, src, w); - src += src_pitch; - dst += dst_pitch; - } + SDL_ConvertPixels(rect->w, rect->h, format, pixels, pitch, + data->format, data->surface.pixels, data->surface.pitch); data->renderer->UnlockTexture(data->renderer, data->texture[data->current_texture]); diff --git a/src/video/SDL_sysvideo.h b/src/video/SDL_sysvideo.h index 65c2a96ce..410a935ef 100644 --- a/src/video/SDL_sysvideo.h +++ b/src/video/SDL_sysvideo.h @@ -97,9 +97,9 @@ struct SDL_Renderer int (*RenderCopy) (SDL_Renderer * renderer, SDL_Texture * texture, const SDL_Rect * srcrect, const SDL_Rect * dstrect); int (*RenderReadPixels) (SDL_Renderer * renderer, const SDL_Rect * rect, - void * pixels, int pitch); + Uint32 format, void * pixels, int pitch); int (*RenderWritePixels) (SDL_Renderer * renderer, const SDL_Rect * rect, - const void * pixels, int pitch); + Uint32 format, const void * pixels, int pitch); void (*RenderPresent) (SDL_Renderer * renderer); void (*DestroyTexture) (SDL_Renderer * renderer, SDL_Texture * texture); diff --git a/src/video/SDL_video.c b/src/video/SDL_video.c index c22cddb16..877371828 100644 --- a/src/video/SDL_video.c +++ b/src/video/SDL_video.c @@ -2487,7 +2487,8 @@ SDL_RenderCopy(SDL_TextureID textureID, const SDL_Rect * srcrect, } int -SDL_RenderReadPixels(const SDL_Rect * rect, void * pixels, int pitch) +SDL_RenderReadPixels(const SDL_Rect * rect, Uint32 format, + void * pixels, int pitch) { SDL_Renderer *renderer; SDL_Window *window; @@ -2503,6 +2504,10 @@ SDL_RenderReadPixels(const SDL_Rect * rect, void * pixels, int pitch) } window = SDL_GetWindowFromID(renderer->window); + if (!format) { + format = SDL_GetDisplayFromWindow(window)->current_mode.format; + } + real_rect.x = 0; real_rect.y = 0; real_rect.w = window->w; @@ -2521,11 +2526,13 @@ SDL_RenderReadPixels(const SDL_Rect * rect, void * pixels, int pitch) } } - return renderer->RenderReadPixels(renderer, &real_rect, pixels, pitch); + return renderer->RenderReadPixels(renderer, &real_rect, + format, pixels, pitch); } int -SDL_RenderWritePixels(const SDL_Rect * rect, const void * pixels, int pitch) +SDL_RenderWritePixels(const SDL_Rect * rect, Uint32 format, + const void * pixels, int pitch) { SDL_Renderer *renderer; SDL_Window *window; @@ -2541,6 +2548,10 @@ SDL_RenderWritePixels(const SDL_Rect * rect, const void * pixels, int pitch) } window = SDL_GetWindowFromID(renderer->window); + if (!format) { + format = SDL_GetDisplayFromWindow(window)->current_mode.format; + } + real_rect.x = 0; real_rect.y = 0; real_rect.w = window->w; @@ -2559,7 +2570,8 @@ SDL_RenderWritePixels(const SDL_Rect * rect, const void * pixels, int pitch) } } - return renderer->RenderWritePixels(renderer, &real_rect, pixels, pitch); + return renderer->RenderWritePixels(renderer, &real_rect, + format, pixels, pitch); } void diff --git a/test/automated/common/common.h b/test/automated/common/common.h index 82c0fcb98..653f83727 100644 --- a/test/automated/common/common.h +++ b/test/automated/common/common.h @@ -12,11 +12,13 @@ #if (SDL_BYTEORDER == SDL_BIG_ENDIAN) +# define FORMAT SDL_PIXELFORMAT_RGBA8888 # define RMASK 0xff000000 /**< Red bit mask. */ # define GMASK 0x00ff0000 /**< Green bit mask. */ # define BMASK 0x0000ff00 /**< Blue bit mask. */ # define AMASK 0x000000ff /**< Alpha bit mask. */ #else +# define FORMAT SDL_PIXELFORMAT_ABGR8888 # define RMASK 0x000000ff /**< Red bit mask. */ # define GMASK 0x0000ff00 /**< Green bit mask. */ # define BMASK 0x00ff0000 /**< Blue bit mask. */ diff --git a/test/automated/render/render.c b/test/automated/render/render.c index 0298b3f3e..de2ddb59f 100644 --- a/test/automated/render/render.c +++ b/test/automated/render/render.c @@ -67,7 +67,7 @@ static int render_compare( const char *msg, const SurfaceImage_t *s ) return 1; /* Read pixels. */ - ret = SDL_RenderReadPixels( NULL, pix, 80*4 ); + ret = SDL_RenderReadPixels( NULL, FORMAT, pix, 80*4 ); if (SDL_ATassert( "SDL_RenderReadPixels", ret==0) ) return 1;