Mercurial > sdl-ios-xcode
diff src/render/SDL_render.c @ 5157:fb424691cfc7
Moved the rendering code out to a separate directory in the hope that it can someday be completely decoupled from the rest of the library and be expanded to an awesome 2D on 3D library.
author | Sam Lantinga <slouken@libsdl.org> |
---|---|
date | Wed, 02 Feb 2011 14:34:54 -0800 |
parents | |
children | 307ccc9c135e |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/render/SDL_render.c Wed Feb 02 14:34:54 2011 -0800 @@ -0,0 +1,1113 @@ +/* + SDL - Simple DirectMedia Layer + Copyright (C) 1997-2010 Sam Lantinga + + 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.1 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + Sam Lantinga + slouken@libsdl.org +*/ +#include "SDL_config.h" + +/* The SDL 2D rendering system */ + +#include "SDL_render.h" +#include "SDL_sysrender.h" +#include "../video/SDL_pixels_c.h" + + +#define CHECK_RENDERER_MAGIC(renderer, retval) \ + if (!renderer || renderer->magic != &renderer_magic) { \ + SDL_SetError("Invalid renderer"); \ + return retval; \ + } + +#define CHECK_TEXTURE_MAGIC(texture, retval) \ + if (!texture || texture->magic != &texture_magic) { \ + SDL_SetError("Invalid texture"); \ + return retval; \ + } + + +static const SDL_RenderDriver *render_drivers[] = { +#if SDL_VIDEO_RENDER_D3D + &D3D_RenderDriver, +#endif +#if SDL_VIDEO_RENDER_OGL + &GL_RenderDriver, +#endif +#if SDL_VIDEO_RENDER_OGL_ES + &GL_ES_RenderDriver, +#endif + &SW_RenderDriver +}; +static char renderer_magic; +static char texture_magic; + +int +SDL_GetNumRenderDrivers(void) +{ + return SDL_arraysize(render_drivers); +} + +int +SDL_GetRenderDriverInfo(int index, SDL_RendererInfo * info) +{ + if (index < 0 || index >= SDL_GetNumRenderDrivers()) { + SDL_SetError("index must be in the range of 0 - %d", + SDL_GetNumRenderDrivers() - 1); + return -1; + } + *info = render_drivers[index]->info; + return 0; +} + +static int +SDL_RendererEventWatch(void *userdata, SDL_Event *event) +{ + SDL_Renderer *renderer = (SDL_Renderer *)userdata; + + if (event->type == SDL_WINDOWEVENT && renderer->WindowEvent) { + SDL_Window *window = SDL_GetWindowFromID(event->window.windowID); + if (window == renderer->window) { + renderer->WindowEvent(renderer, &event->window); + } + } + return 0; +} + +SDL_Renderer * +SDL_CreateRenderer(SDL_Window * window, int index, Uint32 flags) +{ + SDL_Renderer *renderer = NULL; + int n = SDL_GetNumRenderDrivers(); + + if (index < 0) { + char *override = SDL_getenv("SDL_VIDEO_RENDERER"); + + if (override) { + for (index = 0; index < n; ++index) { + const SDL_RenderDriver *driver = render_drivers[index]; + + if (SDL_strcasecmp(override, driver->info.name) == 0) { + /* Create a new renderer instance */ + renderer = driver->CreateRenderer(window, flags); + break; + } + } + } else { + for (index = 0; index < n; ++index) { + const SDL_RenderDriver *driver = render_drivers[index]; + + if ((driver->info.flags & flags) == flags) { + /* Create a new renderer instance */ + renderer = driver->CreateRenderer(window, flags); + if (renderer) { + /* Yay, we got one! */ + break; + } + } + } + } + if (index == n) { + SDL_SetError("Couldn't find matching render driver"); + return NULL; + } + } else { + if (index >= SDL_GetNumRenderDrivers()) { + SDL_SetError("index must be -1 or in the range of 0 - %d", + SDL_GetNumRenderDrivers() - 1); + return NULL; + } + /* Create a new renderer instance */ + renderer = render_drivers[index]->CreateRenderer(window, flags); + } + + if (renderer) { + renderer->magic = &renderer_magic; + + SDL_AddEventWatch(SDL_RendererEventWatch, renderer); + } + return renderer; +} + +int +SDL_GetRendererInfo(SDL_Renderer * renderer, SDL_RendererInfo * info) +{ + CHECK_RENDERER_MAGIC(renderer, -1); + + *info = renderer->info; + return 0; +} + +SDL_Texture * +SDL_CreateTexture(SDL_Renderer * renderer, Uint32 format, int access, int w, int h) +{ + SDL_Texture *texture; + + CHECK_RENDERER_MAGIC(renderer, NULL); + + if (w <= 0 || h <= 0) { + SDL_SetError("Texture dimensions can't be 0"); + return 0; + } + texture = (SDL_Texture *) SDL_calloc(1, sizeof(*texture)); + if (!texture) { + SDL_OutOfMemory(); + return 0; + } + texture->magic = &texture_magic; + texture->format = format; + texture->access = access; + texture->w = w; + texture->h = h; + texture->r = 255; + texture->g = 255; + texture->b = 255; + texture->a = 255; + texture->renderer = renderer; + texture->next = renderer->textures; + if (renderer->textures) { + renderer->textures->prev = texture; + } + renderer->textures = texture; + + if (renderer->CreateTexture(renderer, texture) < 0) { + SDL_DestroyTexture(texture); + return 0; + } + return texture; +} + +SDL_Texture * +SDL_CreateTextureFromSurface(SDL_Renderer * renderer, Uint32 format, SDL_Surface * surface) +{ + SDL_Texture *texture; + Uint32 requested_format = format; + SDL_PixelFormat *fmt; + int bpp; + Uint32 Rmask, Gmask, Bmask, Amask; + + CHECK_RENDERER_MAGIC(renderer, NULL); + + if (!surface) { + SDL_SetError("SDL_CreateTextureFromSurface() passed NULL surface"); + return NULL; + } + fmt = surface->format; + + if (format) { + if (!SDL_PixelFormatEnumToMasks + (format, &bpp, &Rmask, &Gmask, &Bmask, &Amask)) { + SDL_SetError("Unknown pixel format"); + return 0; + } + } else { + SDL_bool hasColorkey; + SDL_BlendMode blendMode; + SDL_bool hasBlending; + + hasColorkey = (SDL_GetColorKey(surface, NULL) == 0); + + SDL_GetSurfaceBlendMode(surface, &blendMode); + hasBlending = (blendMode == SDL_BLENDMODE_BLEND); + + if (surface->format->Amask || (!hasColorkey && !hasBlending)) { + Uint32 it; + int pfmt; + + /* Pixel formats, sorted by best first */ + static const Uint32 sdl_pformats[] = { + SDL_PIXELFORMAT_ARGB8888, + SDL_PIXELFORMAT_RGBA8888, + SDL_PIXELFORMAT_ABGR8888, + SDL_PIXELFORMAT_BGRA8888, + SDL_PIXELFORMAT_RGB888, + SDL_PIXELFORMAT_BGR888, + SDL_PIXELFORMAT_RGB24, + SDL_PIXELFORMAT_BGR24, + SDL_PIXELFORMAT_RGB565, + SDL_PIXELFORMAT_BGR565, + SDL_PIXELFORMAT_ARGB1555, + SDL_PIXELFORMAT_RGBA5551, + SDL_PIXELFORMAT_ABGR1555, + SDL_PIXELFORMAT_BGRA5551, + SDL_PIXELFORMAT_RGB555, + SDL_PIXELFORMAT_BGR555, + SDL_PIXELFORMAT_ARGB4444, + SDL_PIXELFORMAT_RGBA4444, + SDL_PIXELFORMAT_ABGR4444, + SDL_PIXELFORMAT_BGRA4444, + SDL_PIXELFORMAT_RGB444, + SDL_PIXELFORMAT_ARGB2101010, + SDL_PIXELFORMAT_RGB332, + SDL_PIXELFORMAT_UNKNOWN + }; + + bpp = fmt->BitsPerPixel; + Rmask = fmt->Rmask; + Gmask = fmt->Gmask; + Bmask = fmt->Bmask; + Amask = fmt->Amask; + + format = + SDL_MasksToPixelFormatEnum(bpp, Rmask, Gmask, Bmask, Amask); + if (!format) { + SDL_SetError("Unknown pixel format"); + return 0; + } + + /* Search requested format in the supported texture */ + /* formats by current renderer */ + for (it = 0; it < renderer->info.num_texture_formats; it++) { + if (renderer->info.texture_formats[it] == format) { + break; + } + } + + /* If requested format can't be found, search any best */ + /* format which renderer provides */ + if (it == renderer->info.num_texture_formats) { + pfmt = 0; + for (;;) { + if (sdl_pformats[pfmt] == SDL_PIXELFORMAT_UNKNOWN) { + break; + } + + for (it = 0; it < renderer->info.num_texture_formats; + it++) { + if (renderer->info.texture_formats[it] == + sdl_pformats[pfmt]) { + break; + } + } + + if (it != renderer->info.num_texture_formats) { + /* The best format has been found */ + break; + } + pfmt++; + } + + /* If any format can't be found, then return an error */ + if (it == renderer->info.num_texture_formats) { + SDL_SetError + ("Any of the supported pixel formats can't be found"); + return 0; + } + + /* Convert found pixel format back to color masks */ + if (SDL_PixelFormatEnumToMasks + (renderer->info.texture_formats[it], &bpp, &Rmask, &Gmask, + &Bmask, &Amask) != SDL_TRUE) { + SDL_SetError("Unknown pixel format"); + return 0; + } + } + } else { + /* Need a format with alpha */ + Uint32 it; + int apfmt; + + /* Pixel formats with alpha, sorted by best first */ + static const Uint32 sdl_alpha_pformats[] = { + SDL_PIXELFORMAT_ARGB8888, + SDL_PIXELFORMAT_RGBA8888, + SDL_PIXELFORMAT_ABGR8888, + SDL_PIXELFORMAT_BGRA8888, + SDL_PIXELFORMAT_ARGB1555, + SDL_PIXELFORMAT_RGBA5551, + SDL_PIXELFORMAT_ABGR1555, + SDL_PIXELFORMAT_BGRA5551, + SDL_PIXELFORMAT_ARGB4444, + SDL_PIXELFORMAT_RGBA4444, + SDL_PIXELFORMAT_ABGR4444, + SDL_PIXELFORMAT_BGRA4444, + SDL_PIXELFORMAT_ARGB2101010, + SDL_PIXELFORMAT_UNKNOWN + }; + + if (surface->format->Amask) { + /* If surface already has alpha, then try an original */ + /* surface format first */ + bpp = fmt->BitsPerPixel; + Rmask = fmt->Rmask; + Gmask = fmt->Gmask; + Bmask = fmt->Bmask; + Amask = fmt->Amask; + } else { + bpp = 32; + Rmask = 0x00FF0000; + Gmask = 0x0000FF00; + Bmask = 0x000000FF; + Amask = 0xFF000000; + } + + format = + SDL_MasksToPixelFormatEnum(bpp, Rmask, Gmask, Bmask, Amask); + if (!format) { + SDL_SetError("Unknown pixel format"); + return 0; + } + + /* Search this format in the supported texture formats */ + /* by current renderer */ + for (it = 0; it < renderer->info.num_texture_formats; it++) { + if (renderer->info.texture_formats[it] == format) { + break; + } + } + + /* If this format can't be found, search any best */ + /* compatible format with alpha which renderer provides */ + if (it == renderer->info.num_texture_formats) { + apfmt = 0; + for (;;) { + if (sdl_alpha_pformats[apfmt] == SDL_PIXELFORMAT_UNKNOWN) { + break; + } + + for (it = 0; it < renderer->info.num_texture_formats; + it++) { + if (renderer->info.texture_formats[it] == + sdl_alpha_pformats[apfmt]) { + break; + } + } + + if (it != renderer->info.num_texture_formats) { + /* Compatible format has been found */ + break; + } + apfmt++; + } + + /* If compatible format can't be found, then return an error */ + if (it == renderer->info.num_texture_formats) { + SDL_SetError("Compatible pixel format can't be found"); + return 0; + } + + /* Convert found pixel format back to color masks */ + if (SDL_PixelFormatEnumToMasks + (renderer->info.texture_formats[it], &bpp, &Rmask, &Gmask, + &Bmask, &Amask) != SDL_TRUE) { + SDL_SetError("Unknown pixel format"); + return 0; + } + } + } + + format = SDL_MasksToPixelFormatEnum(bpp, Rmask, Gmask, Bmask, Amask); + if (!format) { + SDL_SetError("Unknown pixel format"); + return 0; + } + } + + texture = + SDL_CreateTexture(renderer, format, SDL_TEXTUREACCESS_STATIC, + surface->w, surface->h); + if (!texture && !requested_format) { + SDL_DisplayMode desktop_mode; + SDL_GetDesktopDisplayMode(&desktop_mode); + format = desktop_mode.format; + texture = SDL_CreateTexture(renderer, format, SDL_TEXTUREACCESS_STATIC, + surface->w, surface->h); + } + if (!texture) { + return 0; + } + if (bpp == fmt->BitsPerPixel && Rmask == fmt->Rmask && Gmask == fmt->Gmask + && Bmask == fmt->Bmask && Amask == fmt->Amask) { + if (SDL_MUSTLOCK(surface)) { + SDL_LockSurface(surface); + SDL_UpdateTexture(texture, NULL, surface->pixels, + surface->pitch); + SDL_UnlockSurface(surface); + } else { + SDL_UpdateTexture(texture, NULL, surface->pixels, + surface->pitch); + } + } else { + SDL_PixelFormat dst_fmt; + SDL_Surface *dst = NULL; + + /* Set up a destination surface for the texture update */ + SDL_InitFormat(&dst_fmt, bpp, Rmask, Gmask, Bmask, Amask); + dst = SDL_ConvertSurface(surface, &dst_fmt, 0); + if (dst) { + SDL_UpdateTexture(texture, NULL, dst->pixels, dst->pitch); + SDL_FreeSurface(dst); + } + if (!dst) { + SDL_DestroyTexture(texture); + return 0; + } + } + + { + Uint8 r, g, b, a; + SDL_BlendMode blendMode; + + SDL_GetSurfaceColorMod(surface, &r, &g, &b); + SDL_SetTextureColorMod(texture, r, g, b); + + SDL_GetSurfaceAlphaMod(surface, &a); + SDL_SetTextureAlphaMod(texture, a); + + if (SDL_GetColorKey(surface, NULL) == 0) { + /* We converted to a texture with alpha format */ + SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_BLEND); + } else { + SDL_GetSurfaceBlendMode(surface, &blendMode); + SDL_SetTextureBlendMode(texture, blendMode); + } + } + return texture; +} + +int +SDL_QueryTexture(SDL_Texture * texture, Uint32 * format, int *access, + int *w, int *h) +{ + CHECK_TEXTURE_MAGIC(texture, -1); + + if (format) { + *format = texture->format; + } + if (access) { + *access = texture->access; + } + if (w) { + *w = texture->w; + } + if (h) { + *h = texture->h; + } + return 0; +} + +int +SDL_QueryTexturePixels(SDL_Texture * texture, void **pixels, int *pitch) +{ + SDL_Renderer *renderer; + + CHECK_TEXTURE_MAGIC(texture, -1); + + renderer = texture->renderer; + if (!renderer->QueryTexturePixels) { + SDL_Unsupported(); + return -1; + } + return renderer->QueryTexturePixels(renderer, texture, pixels, pitch); +} + +int +SDL_SetTextureColorMod(SDL_Texture * texture, Uint8 r, Uint8 g, Uint8 b) +{ + SDL_Renderer *renderer; + + CHECK_TEXTURE_MAGIC(texture, -1); + + renderer = texture->renderer; + if (r < 255 || g < 255 || b < 255) { + texture->modMode |= SDL_TEXTUREMODULATE_COLOR; + } else { + texture->modMode &= ~SDL_TEXTUREMODULATE_COLOR; + } + texture->r = r; + texture->g = g; + texture->b = b; + if (renderer->SetTextureColorMod) { + return renderer->SetTextureColorMod(renderer, texture); + } else { + return 0; + } +} + +int +SDL_GetTextureColorMod(SDL_Texture * texture, Uint8 * r, Uint8 * g, + Uint8 * b) +{ + SDL_Renderer *renderer; + + CHECK_TEXTURE_MAGIC(texture, -1); + + renderer = texture->renderer; + if (r) { + *r = texture->r; + } + if (g) { + *g = texture->g; + } + if (b) { + *b = texture->b; + } + return 0; +} + +int +SDL_SetTextureAlphaMod(SDL_Texture * texture, Uint8 alpha) +{ + SDL_Renderer *renderer; + + CHECK_TEXTURE_MAGIC(texture, -1); + + renderer = texture->renderer; + if (alpha < 255) { + texture->modMode |= SDL_TEXTUREMODULATE_ALPHA; + } else { + texture->modMode &= ~SDL_TEXTUREMODULATE_ALPHA; + } + texture->a = alpha; + if (renderer->SetTextureAlphaMod) { + return renderer->SetTextureAlphaMod(renderer, texture); + } else { + return 0; + } +} + +int +SDL_GetTextureAlphaMod(SDL_Texture * texture, Uint8 * alpha) +{ + CHECK_TEXTURE_MAGIC(texture, -1); + + if (alpha) { + *alpha = texture->a; + } + return 0; +} + +int +SDL_SetTextureBlendMode(SDL_Texture * texture, SDL_BlendMode blendMode) +{ + SDL_Renderer *renderer; + + CHECK_TEXTURE_MAGIC(texture, -1); + + renderer = texture->renderer; + texture->blendMode = blendMode; + if (renderer->SetTextureBlendMode) { + return renderer->SetTextureBlendMode(renderer, texture); + } else { + return 0; + } +} + +int +SDL_GetTextureBlendMode(SDL_Texture * texture, SDL_BlendMode *blendMode) +{ + CHECK_TEXTURE_MAGIC(texture, -1); + + if (blendMode) { + *blendMode = texture->blendMode; + } + return 0; +} + +int +SDL_UpdateTexture(SDL_Texture * texture, const SDL_Rect * rect, + const void *pixels, int pitch) +{ + SDL_Renderer *renderer; + SDL_Rect full_rect; + + CHECK_TEXTURE_MAGIC(texture, -1); + + renderer = texture->renderer; + if (!renderer->UpdateTexture) { + SDL_Unsupported(); + return -1; + } + if (!rect) { + full_rect.x = 0; + full_rect.y = 0; + full_rect.w = texture->w; + full_rect.h = texture->h; + rect = &full_rect; + } + return renderer->UpdateTexture(renderer, texture, rect, pixels, pitch); +} + +int +SDL_LockTexture(SDL_Texture * texture, const SDL_Rect * rect, int markDirty, + void **pixels, int *pitch) +{ + SDL_Renderer *renderer; + SDL_Rect full_rect; + + CHECK_TEXTURE_MAGIC(texture, -1); + + if (texture->access != SDL_TEXTUREACCESS_STREAMING) { + SDL_SetError("SDL_LockTexture(): texture must be streaming"); + return -1; + } + renderer = texture->renderer; + if (!renderer->LockTexture) { + SDL_Unsupported(); + return -1; + } + if (!rect) { + full_rect.x = 0; + full_rect.y = 0; + full_rect.w = texture->w; + full_rect.h = texture->h; + rect = &full_rect; + } + return renderer->LockTexture(renderer, texture, rect, markDirty, pixels, + pitch); +} + +void +SDL_UnlockTexture(SDL_Texture * texture) +{ + SDL_Renderer *renderer; + + CHECK_TEXTURE_MAGIC(texture, ); + + if (texture->access != SDL_TEXTUREACCESS_STREAMING) { + return; + } + renderer = texture->renderer; + if (!renderer->UnlockTexture) { + return; + } + renderer->UnlockTexture(renderer, texture); +} + +void +SDL_DirtyTexture(SDL_Texture * texture, int numrects, + const SDL_Rect * rects) +{ + SDL_Renderer *renderer; + + CHECK_TEXTURE_MAGIC(texture, ); + + if (texture->access != SDL_TEXTUREACCESS_STREAMING) { + return; + } + renderer = texture->renderer; + if (!renderer->DirtyTexture) { + return; + } + renderer->DirtyTexture(renderer, texture, numrects, rects); +} + +int +SDL_SetRenderDrawColor(SDL_Renderer * renderer, + Uint8 r, Uint8 g, Uint8 b, Uint8 a) +{ + CHECK_RENDERER_MAGIC(renderer, -1); + + renderer->r = r; + renderer->g = g; + renderer->b = b; + renderer->a = a; + return 0; +} + +int +SDL_GetRenderDrawColor(SDL_Renderer * renderer, + Uint8 * r, Uint8 * g, Uint8 * b, Uint8 * a) +{ + CHECK_RENDERER_MAGIC(renderer, -1); + + if (r) { + *r = renderer->r; + } + if (g) { + *g = renderer->g; + } + if (b) { + *b = renderer->b; + } + if (a) { + *a = renderer->a; + } + return 0; +} + +int +SDL_SetRenderDrawBlendMode(SDL_Renderer * renderer, SDL_BlendMode blendMode) +{ + CHECK_RENDERER_MAGIC(renderer, -1); + + renderer->blendMode = blendMode; + return 0; +} + +int +SDL_GetRenderDrawBlendMode(SDL_Renderer * renderer, SDL_BlendMode *blendMode) +{ + CHECK_RENDERER_MAGIC(renderer, -1); + + *blendMode = renderer->blendMode; + return 0; +} + +int +SDL_RenderClear(SDL_Renderer * renderer) +{ + CHECK_RENDERER_MAGIC(renderer, -1); + + if (!renderer->RenderClear) { + SDL_BlendMode blendMode = renderer->blendMode; + int status; + + if (blendMode >= SDL_BLENDMODE_BLEND) { + SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_NONE); + } + + status = SDL_RenderFillRect(renderer, NULL); + + if (blendMode >= SDL_BLENDMODE_BLEND) { + SDL_SetRenderDrawBlendMode(renderer, blendMode); + } + return status; + } + return renderer->RenderClear(renderer); +} + +int +SDL_RenderDrawPoint(SDL_Renderer * renderer, int x, int y) +{ + SDL_Point point; + + point.x = x; + point.y = y; + return SDL_RenderDrawPoints(renderer, &point, 1); +} + +int +SDL_RenderDrawPoints(SDL_Renderer * renderer, + const SDL_Point * points, int count) +{ + CHECK_RENDERER_MAGIC(renderer, -1); + + if (!points) { + SDL_SetError("SDL_RenderDrawPoints(): Passed NULL points"); + return -1; + } + if (count < 1) { + return 0; + } + return renderer->RenderDrawPoints(renderer, points, count); +} + +int +SDL_RenderDrawLine(SDL_Renderer * renderer, int x1, int y1, int x2, int y2) +{ + SDL_Point points[2]; + + points[0].x = x1; + points[0].y = y1; + points[1].x = x2; + points[1].y = y2; + return SDL_RenderDrawLines(renderer, points, 2); +} + +int +SDL_RenderDrawLines(SDL_Renderer * renderer, + const SDL_Point * points, int count) +{ + CHECK_RENDERER_MAGIC(renderer, -1); + + if (!points) { + SDL_SetError("SDL_RenderDrawLines(): Passed NULL points"); + return -1; + } + if (count < 2) { + return 0; + } + return renderer->RenderDrawLines(renderer, points, count); +} + +int +SDL_RenderDrawRect(SDL_Renderer * renderer, const SDL_Rect * rect) +{ + SDL_Rect full_rect; + SDL_Point points[5]; + + CHECK_RENDERER_MAGIC(renderer, -1); + + /* If 'rect' == NULL, then outline the whole surface */ + if (!rect) { + SDL_Window *window = renderer->window; + + full_rect.x = 0; + full_rect.y = 0; + SDL_GetWindowSize(window, &full_rect.w, &full_rect.h); + rect = &full_rect; + } + + points[0].x = rect->x; + points[0].y = rect->y; + points[1].x = rect->x+rect->w-1; + points[1].y = rect->y; + points[2].x = rect->x+rect->w-1; + points[2].y = rect->y+rect->h-1; + points[3].x = rect->x; + points[3].y = rect->y+rect->h-1; + points[4].x = rect->x; + points[4].y = rect->y; + return SDL_RenderDrawLines(renderer, points, 5); +} + +int +SDL_RenderDrawRects(SDL_Renderer * renderer, + const SDL_Rect ** rects, int count) +{ + int i; + + CHECK_RENDERER_MAGIC(renderer, -1); + + if (!rects) { + SDL_SetError("SDL_RenderDrawRects(): Passed NULL rects"); + return -1; + } + if (count < 1) { + return 0; + } + + /* Check for NULL rect, which means fill entire window */ + for (i = 0; i < count; ++i) { + if (SDL_RenderDrawRect(renderer, rects[i]) < 0) { + return -1; + } + } + return 0; +} + +int +SDL_RenderFillRect(SDL_Renderer * renderer, const SDL_Rect * rect) +{ + return SDL_RenderFillRects(renderer, &rect, 1); +} + +int +SDL_RenderFillRects(SDL_Renderer * renderer, + const SDL_Rect ** rects, int count) +{ + int i; + + CHECK_RENDERER_MAGIC(renderer, -1); + + if (!rects) { + SDL_SetError("SDL_RenderFillRects(): Passed NULL rects"); + return -1; + } + if (count < 1) { + return 0; + } + + /* Check for NULL rect, which means fill entire window */ + for (i = 0; i < count; ++i) { + if (rects[i] == NULL) { + SDL_Window *window = renderer->window; + SDL_Rect full_rect; + const SDL_Rect *rect; + + full_rect.x = 0; + full_rect.y = 0; + SDL_GetWindowSize(window, &full_rect.w, &full_rect.h); + rect = &full_rect; + return renderer->RenderFillRects(renderer, &rect, 1); + } + } + return renderer->RenderFillRects(renderer, rects, count); +} + +int +SDL_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture, + const SDL_Rect * srcrect, const SDL_Rect * dstrect) +{ + SDL_Window *window; + SDL_Rect real_srcrect; + SDL_Rect real_dstrect; + + CHECK_RENDERER_MAGIC(renderer, -1); + CHECK_TEXTURE_MAGIC(texture, -1); + + if (renderer != texture->renderer) { + SDL_SetError("Texture was not created with this renderer"); + return -1; + } + window = renderer->window; + + real_srcrect.x = 0; + real_srcrect.y = 0; + real_srcrect.w = texture->w; + real_srcrect.h = texture->h; + if (srcrect) { + if (!SDL_IntersectRect(srcrect, &real_srcrect, &real_srcrect)) { + return 0; + } + } + + real_dstrect.x = 0; + real_dstrect.y = 0; + SDL_GetWindowSize(window, &real_dstrect.w, &real_dstrect.h); + if (dstrect) { + if (!SDL_IntersectRect(dstrect, &real_dstrect, &real_dstrect)) { + return 0; + } + /* Clip srcrect by the same amount as dstrect was clipped */ + if (dstrect->w != real_dstrect.w) { + int deltax = (real_dstrect.x - dstrect->x); + int deltaw = (real_dstrect.w - dstrect->w); + real_srcrect.x += (deltax * real_srcrect.w) / dstrect->w; + real_srcrect.w += (deltaw * real_srcrect.w) / dstrect->w; + } + if (dstrect->h != real_dstrect.h) { + int deltay = (real_dstrect.y - dstrect->y); + int deltah = (real_dstrect.h - dstrect->h); + real_srcrect.y += (deltay * real_srcrect.h) / dstrect->h; + real_srcrect.h += (deltah * real_srcrect.h) / dstrect->h; + } + } + + return renderer->RenderCopy(renderer, texture, &real_srcrect, + &real_dstrect); +} + +int +SDL_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect, + Uint32 format, void * pixels, int pitch) +{ + SDL_Window *window; + SDL_Rect real_rect; + + CHECK_RENDERER_MAGIC(renderer, -1); + + if (!renderer->RenderReadPixels) { + SDL_Unsupported(); + return -1; + } + window = renderer->window; + + if (!format) { + format = SDL_GetWindowPixelFormat(window); + } + + real_rect.x = 0; + real_rect.y = 0; + SDL_GetWindowSize(window, &real_rect.w, &real_rect.h); + if (rect) { + if (!SDL_IntersectRect(rect, &real_rect, &real_rect)) { + return 0; + } + if (real_rect.y > rect->y) { + pixels = (Uint8 *)pixels + pitch * (real_rect.y - rect->y); + } + if (real_rect.x > rect->x) { + int bpp = SDL_BYTESPERPIXEL(SDL_GetWindowPixelFormat(window)); + pixels = (Uint8 *)pixels + bpp * (real_rect.x - rect->x); + } + } + + return renderer->RenderReadPixels(renderer, &real_rect, + format, pixels, pitch); +} + +int +SDL_RenderWritePixels(SDL_Renderer * renderer, const SDL_Rect * rect, + Uint32 format, const void * pixels, int pitch) +{ + SDL_Window *window; + SDL_Rect real_rect; + + CHECK_RENDERER_MAGIC(renderer, -1); + + if (!renderer->RenderWritePixels) { + SDL_Unsupported(); + return -1; + } + window = renderer->window; + + if (!format) { + format = SDL_GetWindowPixelFormat(window); + } + + real_rect.x = 0; + real_rect.y = 0; + SDL_GetWindowSize(window, &real_rect.w, &real_rect.h); + if (rect) { + if (!SDL_IntersectRect(rect, &real_rect, &real_rect)) { + return 0; + } + if (real_rect.y > rect->y) { + pixels = (const Uint8 *)pixels + pitch * (real_rect.y - rect->y); + } + if (real_rect.x > rect->x) { + int bpp = SDL_BYTESPERPIXEL(SDL_GetWindowPixelFormat(window)); + pixels = (const Uint8 *)pixels + bpp * (real_rect.x - rect->x); + } + } + + return renderer->RenderWritePixels(renderer, &real_rect, + format, pixels, pitch); +} + +void +SDL_RenderPresent(SDL_Renderer * renderer) +{ + CHECK_RENDERER_MAGIC(renderer, ); + + renderer->RenderPresent(renderer); +} + +void +SDL_DestroyTexture(SDL_Texture * texture) +{ + SDL_Renderer *renderer; + + CHECK_TEXTURE_MAGIC(texture, ); + texture->magic = NULL; + + renderer = texture->renderer; + if (texture->next) { + texture->next->prev = texture->prev; + } + if (texture->prev) { + texture->prev->next = texture->next; + } else { + renderer->textures = texture->next; + } + + renderer->DestroyTexture(renderer, texture); + SDL_free(texture); +} + +void +SDL_DestroyRenderer(SDL_Renderer * renderer) +{ + CHECK_RENDERER_MAGIC(renderer, ); + + SDL_DelEventWatch(SDL_RendererEventWatch, renderer); + + /* Free existing textures for this renderer */ + while (renderer->textures) { + SDL_DestroyTexture(renderer->textures); + } + + /* It's no longer magical... */ + renderer->magic = NULL; + + /* Free the renderer instance */ + renderer->DestroyRenderer(renderer); +} + +/* vi: set ts=4 sw=4 expandtab: */