src/render/SDL_render.c
author Sam Lantinga <slouken@libsdl.org>
Fri, 12 Oct 2012 02:20:10 -0700
changeset 6578 77d70ec131bc
parent 6546 824535ce51b6
child 6579 2390a7403b77
permissions -rw-r--r--
Added SDL_GetRenderTarget() API function
Also fixed a bug with setting logical size for a render target.
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2012 Sam Lantinga <slouken@libsdl.org>
     4 
     5   This software is provided 'as-is', without any express or implied
     6   warranty.  In no event will the authors be held liable for any damages
     7   arising from the use of this software.
     8 
     9   Permission is granted to anyone to use this software for any purpose,
    10   including commercial applications, and to alter it and redistribute it
    11   freely, subject to the following restrictions:
    12 
    13   1. The origin of this software must not be misrepresented; you must not
    14      claim that you wrote the original software. If you use this software
    15      in a product, an acknowledgment in the product documentation would be
    16      appreciated but is not required.
    17   2. Altered source versions must be plainly marked as such, and must not be
    18      misrepresented as being the original software.
    19   3. This notice may not be removed or altered from any source distribution.
    20 */
    21 #include "SDL_config.h"
    22 
    23 /* The SDL 2D rendering system */
    24 
    25 #include "SDL_hints.h"
    26 #include "SDL_log.h"
    27 #include "SDL_render.h"
    28 #include "SDL_sysrender.h"
    29 #include "software/SDL_render_sw_c.h"
    30 
    31 
    32 #define SDL_WINDOWRENDERDATA    "_SDL_WindowRenderData"
    33 
    34 #define CHECK_RENDERER_MAGIC(renderer, retval) \
    35     if (!renderer || renderer->magic != &renderer_magic) { \
    36         SDL_SetError("Invalid renderer"); \
    37         return retval; \
    38     }
    39 
    40 #define CHECK_TEXTURE_MAGIC(texture, retval) \
    41     if (!texture || texture->magic != &texture_magic) { \
    42         SDL_SetError("Invalid texture"); \
    43         return retval; \
    44     }
    45 
    46 
    47 static const SDL_RenderDriver *render_drivers[] = {
    48 #if !SDL_RENDER_DISABLED
    49 #if SDL_VIDEO_RENDER_D3D
    50     &D3D_RenderDriver,
    51 #endif
    52 #if SDL_VIDEO_RENDER_OGL
    53     &GL_RenderDriver,
    54 #endif
    55 #if SDL_VIDEO_RENDER_OGL_ES2
    56     &GLES2_RenderDriver,
    57 #endif
    58 #if SDL_VIDEO_RENDER_OGL_ES
    59     &GLES_RenderDriver,
    60 #endif
    61 #if SDL_VIDEO_RENDER_DIRECTFB
    62     &DirectFB_RenderDriver,
    63 #endif
    64 #if SDL_VIDEO_RENDER_NDS
    65     &NDS_RenderDriver,
    66 #endif
    67     &SW_RenderDriver
    68 #endif /* !SDL_RENDER_DISABLED */
    69 };
    70 static char renderer_magic;
    71 static char texture_magic;
    72 
    73 static int UpdateLogicalSize(SDL_Renderer *renderer);
    74 
    75 int
    76 SDL_GetNumRenderDrivers(void)
    77 {
    78     return SDL_arraysize(render_drivers);
    79 }
    80 
    81 int
    82 SDL_GetRenderDriverInfo(int index, SDL_RendererInfo * info)
    83 {
    84     if (index < 0 || index >= SDL_GetNumRenderDrivers()) {
    85         SDL_SetError("index must be in the range of 0 - %d",
    86                      SDL_GetNumRenderDrivers() - 1);
    87         return -1;
    88     }
    89     *info = render_drivers[index]->info;
    90     return 0;
    91 }
    92 
    93 static int
    94 SDL_RendererEventWatch(void *userdata, SDL_Event *event)
    95 {
    96     SDL_Renderer *renderer = (SDL_Renderer *)userdata;
    97 
    98     if (event->type == SDL_WINDOWEVENT) {
    99         SDL_Window *window = SDL_GetWindowFromID(event->window.windowID);
   100         if (window == renderer->window) {
   101             if (renderer->WindowEvent) {
   102                 renderer->WindowEvent(renderer, &event->window);
   103             }
   104 
   105             if (event->window.event == SDL_WINDOWEVENT_RESIZED) {
   106                 if (renderer->logical_w) {
   107                     /* We'll update the renderer in the SIZE_CHANGED event */
   108                 } else {
   109                     /* Try to keep the previous viewport centered */
   110                     int w, h;
   111 
   112                     SDL_GetWindowSize(window, &w, &h);
   113                     if (renderer->target) {
   114                         renderer->viewport_backup.x = (w - renderer->viewport_backup.w) / 2;
   115                         renderer->viewport_backup.y = (h - renderer->viewport_backup.h) / 2;
   116                     } else {
   117                         renderer->viewport.x = (w - renderer->viewport.w) / 2;
   118                         renderer->viewport.y = (h - renderer->viewport.h) / 2;
   119                         renderer->UpdateViewport(renderer);
   120                     }
   121                 }
   122                 renderer->resized = SDL_TRUE;
   123             } else if (event->window.event == SDL_WINDOWEVENT_SIZE_CHANGED) {
   124                 if (renderer->logical_w) {
   125                     UpdateLogicalSize(renderer);
   126                 } else if (!renderer->resized) {
   127                     /* Window was programmatically resized, reset viewport */
   128                     int w, h;
   129 
   130                     SDL_GetWindowSize(window, &w, &h);
   131                     if (renderer->target) {
   132                         renderer->viewport_backup.x = 0;
   133                         renderer->viewport_backup.y = 0;
   134                         renderer->viewport_backup.w = w;
   135                         renderer->viewport_backup.h = h;
   136                     } else {
   137                         renderer->viewport.x = 0;
   138                         renderer->viewport.y = 0;
   139                         renderer->viewport.w = w;
   140                         renderer->viewport.h = h;
   141                         renderer->UpdateViewport(renderer);
   142                     }
   143                 }
   144                 renderer->resized = SDL_FALSE;
   145             } else if (event->window.event == SDL_WINDOWEVENT_HIDDEN) {
   146                 renderer->hidden = SDL_TRUE;
   147             } else if (event->window.event == SDL_WINDOWEVENT_SHOWN) {
   148                 if (!(SDL_GetWindowFlags(window) & SDL_WINDOW_MINIMIZED)) {
   149                     renderer->hidden = SDL_FALSE;
   150                 }
   151             } else if (event->window.event == SDL_WINDOWEVENT_MINIMIZED) {
   152                 renderer->hidden = SDL_TRUE;
   153             } else if (event->window.event == SDL_WINDOWEVENT_RESTORED) {
   154                 if (!(SDL_GetWindowFlags(window) & SDL_WINDOW_HIDDEN)) {
   155                     renderer->hidden = SDL_FALSE;
   156                 }
   157             }
   158         }
   159     } else if (event->type == SDL_MOUSEMOTION) {
   160         if (renderer->logical_w) {
   161             event->motion.x -= renderer->viewport.x;
   162             event->motion.y -= renderer->viewport.y;
   163             event->motion.x = (int)(event->motion.x / renderer->scale.x);
   164             event->motion.y = (int)(event->motion.y / renderer->scale.y);
   165         }
   166     } else if (event->type == SDL_MOUSEBUTTONDOWN ||
   167                event->type == SDL_MOUSEBUTTONUP) {
   168         if (renderer->logical_w) {
   169             event->button.x -= renderer->viewport.x;
   170             event->button.y -= renderer->viewport.y;
   171             event->button.x = (int)(event->button.x / renderer->scale.x);
   172             event->button.y = (int)(event->button.y / renderer->scale.y);
   173         }
   174     }
   175     return 0;
   176 }
   177 
   178 int
   179 SDL_CreateWindowAndRenderer(int width, int height, Uint32 window_flags,
   180                             SDL_Window **window, SDL_Renderer **renderer)
   181 {
   182     *window = SDL_CreateWindow(NULL, SDL_WINDOWPOS_UNDEFINED,
   183                                      SDL_WINDOWPOS_UNDEFINED,
   184                                      width, height, window_flags);
   185     if (!*window) {
   186         *renderer = NULL;
   187         return -1;
   188     }
   189 
   190     *renderer = SDL_CreateRenderer(*window, -1, 0);
   191     if (!*renderer) {
   192         return -1;
   193     }
   194 
   195     return 0;
   196 }
   197 
   198 SDL_Renderer *
   199 SDL_CreateRenderer(SDL_Window * window, int index, Uint32 flags)
   200 {
   201     SDL_Renderer *renderer = NULL;
   202     int n = SDL_GetNumRenderDrivers();
   203     const char *hint;
   204 
   205     if (!window) {
   206         SDL_SetError("Invalid window");
   207         return NULL;
   208     }
   209 
   210     if (SDL_GetRenderer(window)) {
   211         SDL_SetError("Renderer already associated with window");
   212         return NULL;
   213     }
   214 
   215     hint = SDL_GetHint(SDL_HINT_RENDER_VSYNC);
   216     if (hint) {
   217         if (*hint == '0') {
   218             flags &= ~SDL_RENDERER_PRESENTVSYNC;
   219         } else {
   220             flags |= SDL_RENDERER_PRESENTVSYNC;
   221         }
   222     }
   223 
   224     if (index < 0) {
   225         hint = SDL_GetHint(SDL_HINT_RENDER_DRIVER);
   226         if (hint) {
   227             for (index = 0; index < n; ++index) {
   228                 const SDL_RenderDriver *driver = render_drivers[index];
   229 
   230                 if (SDL_strcasecmp(hint, driver->info.name) == 0) {
   231                     /* Create a new renderer instance */
   232                     renderer = driver->CreateRenderer(window, flags);
   233                     break;
   234                 }
   235             }
   236         }
   237 
   238         if (!renderer) {
   239             for (index = 0; index < n; ++index) {
   240                 const SDL_RenderDriver *driver = render_drivers[index];
   241 
   242                 if ((driver->info.flags & flags) == flags) {
   243                     /* Create a new renderer instance */
   244                     renderer = driver->CreateRenderer(window, flags);
   245                     if (renderer) {
   246                         /* Yay, we got one! */
   247                         break;
   248                     }
   249                 }
   250             }
   251         }
   252         if (index == n) {
   253             SDL_SetError("Couldn't find matching render driver");
   254             return NULL;
   255         }
   256     } else {
   257         if (index >= SDL_GetNumRenderDrivers()) {
   258             SDL_SetError("index must be -1 or in the range of 0 - %d",
   259                          SDL_GetNumRenderDrivers() - 1);
   260             return NULL;
   261         }
   262         /* Create a new renderer instance */
   263         renderer = render_drivers[index]->CreateRenderer(window, flags);
   264     }
   265 
   266     if (renderer) {
   267         renderer->magic = &renderer_magic;
   268         renderer->window = window;
   269         renderer->scale.x = 1.0f;
   270         renderer->scale.y = 1.0f;
   271 
   272         if (SDL_GetWindowFlags(window) & (SDL_WINDOW_HIDDEN|SDL_WINDOW_MINIMIZED)) {
   273             renderer->hidden = SDL_TRUE;
   274         } else {
   275             renderer->hidden = SDL_FALSE;
   276         }
   277 
   278         SDL_SetWindowData(window, SDL_WINDOWRENDERDATA, renderer);
   279 
   280         SDL_RenderSetViewport(renderer, NULL);
   281 
   282         SDL_AddEventWatch(SDL_RendererEventWatch, renderer);
   283 
   284         SDL_LogInfo(SDL_LOG_CATEGORY_RENDER,
   285                     "Created renderer: %s", renderer->info.name);
   286     }
   287     return renderer;
   288 }
   289 
   290 SDL_Renderer *
   291 SDL_CreateSoftwareRenderer(SDL_Surface * surface)
   292 {
   293 #if !SDL_RENDER_DISABLED
   294     SDL_Renderer *renderer;
   295 
   296     renderer = SW_CreateRendererForSurface(surface);
   297 
   298     if (renderer) {
   299         renderer->magic = &renderer_magic;
   300         renderer->scale.x = 1.0f;
   301         renderer->scale.y = 1.0f;
   302 
   303         SDL_RenderSetViewport(renderer, NULL);
   304     }
   305     return renderer;
   306 #else
   307     SDL_SetError("SDL not built with rendering support");
   308     return NULL;
   309 #endif /* !SDL_RENDER_DISABLED */
   310 }
   311 
   312 SDL_Renderer *
   313 SDL_GetRenderer(SDL_Window * window)
   314 {
   315     return (SDL_Renderer *)SDL_GetWindowData(window, SDL_WINDOWRENDERDATA);
   316 }
   317 
   318 int
   319 SDL_GetRendererInfo(SDL_Renderer * renderer, SDL_RendererInfo * info)
   320 {
   321     CHECK_RENDERER_MAGIC(renderer, -1);
   322 
   323     *info = renderer->info;
   324     return 0;
   325 }
   326 
   327 static SDL_bool
   328 IsSupportedFormat(SDL_Renderer * renderer, Uint32 format)
   329 {
   330     Uint32 i;
   331 
   332     for (i = 0; i < renderer->info.num_texture_formats; ++i) {
   333         if (renderer->info.texture_formats[i] == format) {
   334             return SDL_TRUE;
   335         }
   336     }
   337     return SDL_FALSE;
   338 }
   339 
   340 static Uint32
   341 GetClosestSupportedFormat(SDL_Renderer * renderer, Uint32 format)
   342 {
   343     Uint32 i;
   344 
   345     if (SDL_ISPIXELFORMAT_FOURCC(format)) {
   346         /* Look for an exact match */
   347         for (i = 0; i < renderer->info.num_texture_formats; ++i) {
   348             if (renderer->info.texture_formats[i] == format) {
   349                 return renderer->info.texture_formats[i];
   350             }
   351         }
   352     } else {
   353         SDL_bool hasAlpha = SDL_ISPIXELFORMAT_ALPHA(format);
   354 
   355         /* We just want to match the first format that has the same channels */
   356         for (i = 0; i < renderer->info.num_texture_formats; ++i) {
   357             if (!SDL_ISPIXELFORMAT_FOURCC(renderer->info.texture_formats[i]) &&
   358                 SDL_ISPIXELFORMAT_ALPHA(renderer->info.texture_formats[i]) == hasAlpha) {
   359                 return renderer->info.texture_formats[i];
   360             }
   361         }
   362     }
   363     return renderer->info.texture_formats[0];
   364 }
   365 
   366 SDL_Texture *
   367 SDL_CreateTexture(SDL_Renderer * renderer, Uint32 format, int access, int w, int h)
   368 {
   369     SDL_Texture *texture;
   370 
   371     CHECK_RENDERER_MAGIC(renderer, NULL);
   372 
   373     if (!format) {
   374         format = renderer->info.texture_formats[0];
   375     }
   376     if (SDL_ISPIXELFORMAT_INDEXED(format)) {
   377         SDL_SetError("Palettized textures are not supported");
   378         return NULL;
   379     }
   380     if (w <= 0 || h <= 0) {
   381         SDL_SetError("Texture dimensions can't be 0");
   382         return NULL;
   383     }
   384     texture = (SDL_Texture *) SDL_calloc(1, sizeof(*texture));
   385     if (!texture) {
   386         SDL_OutOfMemory();
   387         return NULL;
   388     }
   389     texture->magic = &texture_magic;
   390     texture->format = format;
   391     texture->access = access;
   392     texture->w = w;
   393     texture->h = h;
   394     texture->r = 255;
   395     texture->g = 255;
   396     texture->b = 255;
   397     texture->a = 255;
   398     texture->renderer = renderer;
   399     texture->next = renderer->textures;
   400     if (renderer->textures) {
   401         renderer->textures->prev = texture;
   402     }
   403     renderer->textures = texture;
   404 
   405     if (IsSupportedFormat(renderer, format)) {
   406         if (renderer->CreateTexture(renderer, texture) < 0) {
   407             SDL_DestroyTexture(texture);
   408             return 0;
   409         }
   410     } else {
   411         texture->native = SDL_CreateTexture(renderer,
   412                                 GetClosestSupportedFormat(renderer, format),
   413                                 access, w, h);
   414         if (!texture->native) {
   415             SDL_DestroyTexture(texture);
   416             return NULL;
   417         }
   418 
   419         /* Swap textures to have texture before texture->native in the list */
   420         texture->native->next = texture->next;
   421         if (texture->native->next) {
   422             texture->native->next->prev = texture->native;
   423         }
   424         texture->prev = texture->native->prev;
   425         if (texture->prev) {
   426             texture->prev->next = texture;
   427         }
   428         texture->native->prev = texture;
   429         texture->next = texture->native;
   430         renderer->textures = texture;
   431 
   432         if (SDL_ISPIXELFORMAT_FOURCC(texture->format)) {
   433             texture->yuv = SDL_SW_CreateYUVTexture(format, w, h);
   434             if (!texture->yuv) {
   435                 SDL_DestroyTexture(texture);
   436                 return NULL;
   437             }
   438         } else if (access == SDL_TEXTUREACCESS_STREAMING) {
   439             /* The pitch is 4 byte aligned */
   440             texture->pitch = (((w * SDL_BYTESPERPIXEL(format)) + 3) & ~3);
   441             texture->pixels = SDL_calloc(1, texture->pitch * h);
   442             if (!texture->pixels) {
   443                 SDL_DestroyTexture(texture);
   444                 return NULL;
   445             }
   446         }
   447     }
   448     return texture;
   449 }
   450 
   451 SDL_Texture *
   452 SDL_CreateTextureFromSurface(SDL_Renderer * renderer, SDL_Surface * surface)
   453 {
   454     const SDL_PixelFormat *fmt;
   455     SDL_bool needAlpha;
   456     Uint32 i;
   457     Uint32 format;
   458     SDL_Texture *texture;
   459 
   460     CHECK_RENDERER_MAGIC(renderer, NULL);
   461 
   462     if (!surface) {
   463         SDL_SetError("SDL_CreateTextureFromSurface() passed NULL surface");
   464         return NULL;
   465     }
   466 
   467     /* See what the best texture format is */
   468     fmt = surface->format;
   469     if (fmt->Amask || SDL_GetColorKey(surface, NULL) == 0) {
   470         needAlpha = SDL_TRUE;
   471     } else {
   472         needAlpha = SDL_FALSE;
   473     }
   474     format = renderer->info.texture_formats[0];
   475     for (i = 0; i < renderer->info.num_texture_formats; ++i) {
   476         if (!SDL_ISPIXELFORMAT_FOURCC(renderer->info.texture_formats[i]) &&
   477             SDL_ISPIXELFORMAT_ALPHA(renderer->info.texture_formats[i]) == needAlpha) {
   478             format = renderer->info.texture_formats[i];
   479             break;
   480         }
   481     }
   482 
   483     texture = SDL_CreateTexture(renderer, format, SDL_TEXTUREACCESS_STATIC,
   484                                 surface->w, surface->h);
   485     if (!texture) {
   486         return NULL;
   487     }
   488 
   489     if (format == surface->format->format) {
   490         if (SDL_MUSTLOCK(surface)) {
   491             SDL_LockSurface(surface);
   492             SDL_UpdateTexture(texture, NULL, surface->pixels, surface->pitch);
   493             SDL_UnlockSurface(surface);
   494         } else {
   495             SDL_UpdateTexture(texture, NULL, surface->pixels, surface->pitch);
   496         }
   497     } else {
   498         SDL_PixelFormat *dst_fmt;
   499         SDL_Surface *temp = NULL;
   500 
   501         /* Set up a destination surface for the texture update */
   502         dst_fmt = SDL_AllocFormat(format);
   503         temp = SDL_ConvertSurface(surface, dst_fmt, 0);
   504         SDL_FreeFormat(dst_fmt);
   505         if (temp) {
   506             SDL_UpdateTexture(texture, NULL, temp->pixels, temp->pitch);
   507             SDL_FreeSurface(temp);
   508         } else {
   509             SDL_DestroyTexture(texture);
   510             return NULL;
   511         }
   512     }
   513 
   514     {
   515         Uint8 r, g, b, a;
   516         SDL_BlendMode blendMode;
   517 
   518         SDL_GetSurfaceColorMod(surface, &r, &g, &b);
   519         SDL_SetTextureColorMod(texture, r, g, b);
   520 
   521         SDL_GetSurfaceAlphaMod(surface, &a);
   522         SDL_SetTextureAlphaMod(texture, a);
   523 
   524         if (SDL_GetColorKey(surface, NULL) == 0) {
   525             /* We converted to a texture with alpha format */
   526             SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_BLEND);
   527         } else {
   528             SDL_GetSurfaceBlendMode(surface, &blendMode);
   529             SDL_SetTextureBlendMode(texture, blendMode);
   530         }
   531     }
   532     return texture;
   533 }
   534 
   535 int
   536 SDL_QueryTexture(SDL_Texture * texture, Uint32 * format, int *access,
   537                  int *w, int *h)
   538 {
   539     CHECK_TEXTURE_MAGIC(texture, -1);
   540 
   541     if (format) {
   542         *format = texture->format;
   543     }
   544     if (access) {
   545         *access = texture->access;
   546     }
   547     if (w) {
   548         *w = texture->w;
   549     }
   550     if (h) {
   551         *h = texture->h;
   552     }
   553     return 0;
   554 }
   555 
   556 int
   557 SDL_SetTextureColorMod(SDL_Texture * texture, Uint8 r, Uint8 g, Uint8 b)
   558 {
   559     SDL_Renderer *renderer;
   560 
   561     CHECK_TEXTURE_MAGIC(texture, -1);
   562 
   563     renderer = texture->renderer;
   564     if (r < 255 || g < 255 || b < 255) {
   565         texture->modMode |= SDL_TEXTUREMODULATE_COLOR;
   566     } else {
   567         texture->modMode &= ~SDL_TEXTUREMODULATE_COLOR;
   568     }
   569     texture->r = r;
   570     texture->g = g;
   571     texture->b = b;
   572     if (texture->native) {
   573         return SDL_SetTextureColorMod(texture->native, r, g, b);
   574     } else if (renderer->SetTextureColorMod) {
   575         return renderer->SetTextureColorMod(renderer, texture);
   576     } else {
   577         return 0;
   578     }
   579 }
   580 
   581 int
   582 SDL_GetTextureColorMod(SDL_Texture * texture, Uint8 * r, Uint8 * g,
   583                        Uint8 * b)
   584 {
   585     CHECK_TEXTURE_MAGIC(texture, -1);
   586 
   587     if (r) {
   588         *r = texture->r;
   589     }
   590     if (g) {
   591         *g = texture->g;
   592     }
   593     if (b) {
   594         *b = texture->b;
   595     }
   596     return 0;
   597 }
   598 
   599 int
   600 SDL_SetTextureAlphaMod(SDL_Texture * texture, Uint8 alpha)
   601 {
   602     SDL_Renderer *renderer;
   603 
   604     CHECK_TEXTURE_MAGIC(texture, -1);
   605 
   606     renderer = texture->renderer;
   607     if (alpha < 255) {
   608         texture->modMode |= SDL_TEXTUREMODULATE_ALPHA;
   609     } else {
   610         texture->modMode &= ~SDL_TEXTUREMODULATE_ALPHA;
   611     }
   612     texture->a = alpha;
   613     if (texture->native) {
   614         return SDL_SetTextureAlphaMod(texture->native, alpha);
   615     } else if (renderer->SetTextureAlphaMod) {
   616         return renderer->SetTextureAlphaMod(renderer, texture);
   617     } else {
   618         return 0;
   619     }
   620 }
   621 
   622 int
   623 SDL_GetTextureAlphaMod(SDL_Texture * texture, Uint8 * alpha)
   624 {
   625     CHECK_TEXTURE_MAGIC(texture, -1);
   626 
   627     if (alpha) {
   628         *alpha = texture->a;
   629     }
   630     return 0;
   631 }
   632 
   633 int
   634 SDL_SetTextureBlendMode(SDL_Texture * texture, SDL_BlendMode blendMode)
   635 {
   636     SDL_Renderer *renderer;
   637 
   638     CHECK_TEXTURE_MAGIC(texture, -1);
   639 
   640     renderer = texture->renderer;
   641     texture->blendMode = blendMode;
   642     if (texture->native) {
   643         return SDL_SetTextureBlendMode(texture->native, blendMode);
   644     } else if (renderer->SetTextureBlendMode) {
   645         return renderer->SetTextureBlendMode(renderer, texture);
   646     } else {
   647         return 0;
   648     }
   649 }
   650 
   651 int
   652 SDL_GetTextureBlendMode(SDL_Texture * texture, SDL_BlendMode *blendMode)
   653 {
   654     CHECK_TEXTURE_MAGIC(texture, -1);
   655 
   656     if (blendMode) {
   657         *blendMode = texture->blendMode;
   658     }
   659     return 0;
   660 }
   661 
   662 static int
   663 SDL_UpdateTextureYUV(SDL_Texture * texture, const SDL_Rect * rect,
   664                      const void *pixels, int pitch)
   665 {
   666     SDL_Texture *native = texture->native;
   667     SDL_Rect full_rect;
   668 
   669     if (SDL_SW_UpdateYUVTexture(texture->yuv, rect, pixels, pitch) < 0) {
   670         return -1;
   671     }
   672 
   673     full_rect.x = 0;
   674     full_rect.y = 0;
   675     full_rect.w = texture->w;
   676     full_rect.h = texture->h;
   677     rect = &full_rect;
   678 
   679     if (texture->access == SDL_TEXTUREACCESS_STREAMING) {
   680         /* We can lock the texture and copy to it */
   681         void *native_pixels;
   682         int native_pitch;
   683 
   684         if (SDL_LockTexture(native, rect, &native_pixels, &native_pitch) < 0) {
   685             return -1;
   686         }
   687         SDL_SW_CopyYUVToRGB(texture->yuv, rect, native->format,
   688                             rect->w, rect->h, native_pixels, native_pitch);
   689         SDL_UnlockTexture(native);
   690     } else {
   691         /* Use a temporary buffer for updating */
   692         void *temp_pixels;
   693         int temp_pitch;
   694 
   695         temp_pitch = (((rect->w * SDL_BYTESPERPIXEL(native->format)) + 3) & ~3);
   696         temp_pixels = SDL_malloc(rect->h * temp_pitch);
   697         if (!temp_pixels) {
   698             SDL_OutOfMemory();
   699             return -1;
   700         }
   701         SDL_SW_CopyYUVToRGB(texture->yuv, rect, native->format,
   702                             rect->w, rect->h, temp_pixels, temp_pitch);
   703         SDL_UpdateTexture(native, rect, temp_pixels, temp_pitch);
   704         SDL_free(temp_pixels);
   705     }
   706     return 0;
   707 }
   708 
   709 static int
   710 SDL_UpdateTextureNative(SDL_Texture * texture, const SDL_Rect * rect,
   711                         const void *pixels, int pitch)
   712 {
   713     SDL_Texture *native = texture->native;
   714 
   715     if (texture->access == SDL_TEXTUREACCESS_STREAMING) {
   716         /* We can lock the texture and copy to it */
   717         void *native_pixels;
   718         int native_pitch;
   719 
   720         if (SDL_LockTexture(native, rect, &native_pixels, &native_pitch) < 0) {
   721             return -1;
   722         }
   723         SDL_ConvertPixels(rect->w, rect->h,
   724                           texture->format, pixels, pitch,
   725                           native->format, native_pixels, native_pitch);
   726         SDL_UnlockTexture(native);
   727     } else {
   728         /* Use a temporary buffer for updating */
   729         void *temp_pixels;
   730         int temp_pitch;
   731 
   732         temp_pitch = (((rect->w * SDL_BYTESPERPIXEL(native->format)) + 3) & ~3);
   733         temp_pixels = SDL_malloc(rect->h * temp_pitch);
   734         if (!temp_pixels) {
   735             SDL_OutOfMemory();
   736             return -1;
   737         }
   738         SDL_ConvertPixels(rect->w, rect->h,
   739                           texture->format, pixels, pitch,
   740                           native->format, temp_pixels, temp_pitch);
   741         SDL_UpdateTexture(native, rect, temp_pixels, temp_pitch);
   742         SDL_free(temp_pixels);
   743     }
   744     return 0;
   745 }
   746 
   747 int
   748 SDL_UpdateTexture(SDL_Texture * texture, const SDL_Rect * rect,
   749                   const void *pixels, int pitch)
   750 {
   751     SDL_Renderer *renderer;
   752     SDL_Rect full_rect;
   753 
   754     CHECK_TEXTURE_MAGIC(texture, -1);
   755 
   756     if (!rect) {
   757         full_rect.x = 0;
   758         full_rect.y = 0;
   759         full_rect.w = texture->w;
   760         full_rect.h = texture->h;
   761         rect = &full_rect;
   762     }
   763 
   764     if (texture->yuv) {
   765         return SDL_UpdateTextureYUV(texture, rect, pixels, pitch);
   766     } else if (texture->native) {
   767         return SDL_UpdateTextureNative(texture, rect, pixels, pitch);
   768     } else {
   769         renderer = texture->renderer;
   770         return renderer->UpdateTexture(renderer, texture, rect, pixels, pitch);
   771     }
   772 }
   773 
   774 static int
   775 SDL_LockTextureYUV(SDL_Texture * texture, const SDL_Rect * rect,
   776                    void **pixels, int *pitch)
   777 {
   778     return SDL_SW_LockYUVTexture(texture->yuv, rect, pixels, pitch);
   779 }
   780 
   781 static int
   782 SDL_LockTextureNative(SDL_Texture * texture, const SDL_Rect * rect,
   783                       void **pixels, int *pitch)
   784 {
   785     texture->locked_rect = *rect;
   786     *pixels = (void *) ((Uint8 *) texture->pixels +
   787                         rect->y * texture->pitch +
   788                         rect->x * SDL_BYTESPERPIXEL(texture->format));
   789     *pitch = texture->pitch;
   790     return 0;
   791 }
   792 
   793 int
   794 SDL_LockTexture(SDL_Texture * texture, const SDL_Rect * rect,
   795                 void **pixels, int *pitch)
   796 {
   797     SDL_Renderer *renderer;
   798     SDL_Rect full_rect;
   799 
   800     CHECK_TEXTURE_MAGIC(texture, -1);
   801 
   802     if (texture->access != SDL_TEXTUREACCESS_STREAMING) {
   803         SDL_SetError("SDL_LockTexture(): texture must be streaming");
   804         return -1;
   805     }
   806 
   807     if (!rect) {
   808         full_rect.x = 0;
   809         full_rect.y = 0;
   810         full_rect.w = texture->w;
   811         full_rect.h = texture->h;
   812         rect = &full_rect;
   813     }
   814 
   815     if (texture->yuv) {
   816         return SDL_LockTextureYUV(texture, rect, pixels, pitch);
   817     } else if (texture->native) {
   818         return SDL_LockTextureNative(texture, rect, pixels, pitch);
   819     } else {
   820         renderer = texture->renderer;
   821         return renderer->LockTexture(renderer, texture, rect, pixels, pitch);
   822     }
   823 }
   824 
   825 static void
   826 SDL_UnlockTextureYUV(SDL_Texture * texture)
   827 {
   828     SDL_Texture *native = texture->native;
   829     void *native_pixels;
   830     int native_pitch;
   831     SDL_Rect rect;
   832 
   833     rect.x = 0;
   834     rect.y = 0;
   835     rect.w = texture->w;
   836     rect.h = texture->h;
   837 
   838     if (SDL_LockTexture(native, &rect, &native_pixels, &native_pitch) < 0) {
   839         return;
   840     }
   841     SDL_SW_CopyYUVToRGB(texture->yuv, &rect, native->format,
   842                         rect.w, rect.h, native_pixels, native_pitch);
   843     SDL_UnlockTexture(native);
   844 }
   845 
   846 static void
   847 SDL_UnlockTextureNative(SDL_Texture * texture)
   848 {
   849     SDL_Texture *native = texture->native;
   850     void *native_pixels;
   851     int native_pitch;
   852     const SDL_Rect *rect = &texture->locked_rect;
   853     const void* pixels = (void *) ((Uint8 *) texture->pixels +
   854                         rect->y * texture->pitch +
   855                         rect->x * SDL_BYTESPERPIXEL(texture->format));
   856     int pitch = texture->pitch;
   857 
   858     if (SDL_LockTexture(native, rect, &native_pixels, &native_pitch) < 0) {
   859         return;
   860     }
   861     SDL_ConvertPixels(rect->w, rect->h,
   862                       texture->format, pixels, pitch,
   863                       native->format, native_pixels, native_pitch);
   864     SDL_UnlockTexture(native);
   865 }
   866 
   867 void
   868 SDL_UnlockTexture(SDL_Texture * texture)
   869 {
   870     SDL_Renderer *renderer;
   871 
   872     CHECK_TEXTURE_MAGIC(texture, );
   873 
   874     if (texture->access != SDL_TEXTUREACCESS_STREAMING) {
   875         return;
   876     }
   877     if (texture->yuv) {
   878         SDL_UnlockTextureYUV(texture);
   879     } else if (texture->native) {
   880         SDL_UnlockTextureNative(texture);
   881     } else {
   882         renderer = texture->renderer;
   883         renderer->UnlockTexture(renderer, texture);
   884     }
   885 }
   886 
   887 SDL_bool
   888 SDL_RenderTargetSupported(SDL_Renderer *renderer)
   889 {
   890     if (!renderer || !renderer->SetRenderTarget) {
   891         return SDL_FALSE;
   892     }
   893     return (renderer->info.flags & SDL_RENDERER_TARGETTEXTURE) != 0;
   894 }
   895 
   896 int
   897 SDL_SetRenderTarget(SDL_Renderer *renderer, SDL_Texture *texture)
   898 {
   899     if (!SDL_RenderTargetSupported(renderer)) {
   900         SDL_Unsupported();
   901         return -1;
   902     }
   903     if (texture == renderer->target) {
   904         /* Nothing to do! */
   905         return 0;
   906     }
   907 
   908     /* texture == NULL is valid and means reset the target to the window */
   909     if (texture) {
   910         CHECK_TEXTURE_MAGIC(texture, -1);
   911         if (renderer != texture->renderer) {
   912             SDL_SetError("Texture was not created with this renderer");
   913             return -1;
   914         }
   915         if (texture->access != SDL_TEXTUREACCESS_TARGET) {
   916             SDL_SetError("Texture not created with SDL_TEXTUREACCESS_TARGET");
   917             return -1;
   918         }
   919         if (texture->native) {
   920             /* Always render to the native texture */
   921             texture = texture->native;
   922         }
   923     }
   924 
   925     if (texture && !renderer->target) {
   926         /* Make a backup of the viewport */
   927         renderer->viewport_backup = renderer->viewport;
   928         renderer->scale_backup = renderer->scale;
   929     }
   930     renderer->target = texture;
   931 
   932     if (renderer->SetRenderTarget(renderer, texture) < 0) {
   933         return -1;
   934     }
   935 
   936     if (texture) {
   937         renderer->viewport.x = 0;
   938         renderer->viewport.y = 0;
   939         renderer->viewport.w = texture->w;
   940         renderer->viewport.h = texture->h;
   941         renderer->scale.x = 1.0f;
   942         renderer->scale.y = 1.0f;
   943     } else {
   944         renderer->viewport = renderer->viewport_backup;
   945         renderer->scale = renderer->scale_backup;
   946     }
   947     if (renderer->UpdateViewport(renderer) < 0) {
   948         return -1;
   949     }
   950 
   951     /* All set! */
   952     return 0;
   953 }
   954 
   955 SDL_Texture *
   956 SDL_GetRenderTarget(SDL_Renderer *renderer)
   957 {
   958     return renderer->target;
   959 }
   960 
   961 static int
   962 UpdateLogicalSize(SDL_Renderer *renderer)
   963 {
   964     int w, h;
   965     float want_aspect;
   966     float real_aspect;
   967     float scale;
   968     SDL_Rect viewport;
   969 
   970     if (renderer->target) {
   971         SDL_QueryTexture(renderer->target, NULL, NULL, &w, &h);
   972     } else if (renderer->window) {
   973         SDL_GetWindowSize(renderer->window, &w, &h);
   974     } else {
   975         /* FIXME */
   976         SDL_SetError("Internal error: No way to get output resolution");
   977         return -1;
   978     }
   979 
   980     want_aspect = (float)renderer->logical_w / renderer->logical_h;
   981     real_aspect = (float)w / h;
   982 
   983     /* Clear the scale because we're setting viewport in output coordinates */
   984     SDL_RenderSetScale(renderer, 1.0f, 1.0f);
   985 
   986     if (SDL_fabs(want_aspect-real_aspect) < 0.0001) {
   987         /* The aspect ratios are the same, just scale appropriately */
   988         scale = (float)w / renderer->logical_w;
   989         SDL_RenderSetViewport(renderer, NULL);
   990     } else if (want_aspect > real_aspect) {
   991         /* We want a wider aspect ratio than is available - letterbox it */
   992         scale = (float)w / renderer->logical_w;
   993         viewport.x = 0;
   994         viewport.w = w;
   995         viewport.h = (int)SDL_ceil(renderer->logical_h * scale);
   996         viewport.y = (h - viewport.h) / 2;
   997         SDL_RenderSetViewport(renderer, &viewport);
   998     } else {
   999         /* We want a narrower aspect ratio than is available - use side-bars */
  1000         scale = (float)h / renderer->logical_h;
  1001         viewport.y = 0;
  1002         viewport.h = h;
  1003         viewport.w = (int)SDL_ceil(renderer->logical_w * scale);
  1004         viewport.x = (w - viewport.w) / 2;
  1005         SDL_RenderSetViewport(renderer, &viewport);
  1006     }
  1007 
  1008     /* Set the new scale */
  1009     SDL_RenderSetScale(renderer, scale, scale);
  1010 
  1011     return 0;
  1012 }
  1013 
  1014 int
  1015 SDL_RenderSetLogicalSize(SDL_Renderer * renderer, int w, int h)
  1016 {
  1017     CHECK_RENDERER_MAGIC(renderer, -1);
  1018 
  1019     if (!w || !h) {
  1020         /* Clear any previous logical resolution */
  1021         renderer->logical_w = 0;
  1022         renderer->logical_h = 0;
  1023         SDL_RenderSetViewport(renderer, NULL);
  1024         SDL_RenderSetScale(renderer, 1.0f, 1.0f);
  1025         return 0;
  1026     }
  1027 
  1028     renderer->logical_w = w;
  1029     renderer->logical_h = h;
  1030 
  1031     return UpdateLogicalSize(renderer);
  1032 }
  1033 
  1034 void
  1035 SDL_RenderGetLogicalSize(SDL_Renderer * renderer, int *w, int *h)
  1036 {
  1037     CHECK_RENDERER_MAGIC(renderer, );
  1038 
  1039     if (w) {
  1040         *w = renderer->logical_w;
  1041     }
  1042     if (h) {
  1043         *h = renderer->logical_h;
  1044     }
  1045 }
  1046 
  1047 int
  1048 SDL_RenderSetViewport(SDL_Renderer * renderer, const SDL_Rect * rect)
  1049 {
  1050     CHECK_RENDERER_MAGIC(renderer, -1);
  1051 
  1052     if (rect) {
  1053         renderer->viewport.x = (int)SDL_floor(rect->x * renderer->scale.x);
  1054         renderer->viewport.y = (int)SDL_floor(rect->y * renderer->scale.y);
  1055         renderer->viewport.w = (int)SDL_ceil(rect->w * renderer->scale.x);
  1056         renderer->viewport.h = (int)SDL_ceil(rect->h * renderer->scale.y);
  1057     } else {
  1058         renderer->viewport.x = 0;
  1059         renderer->viewport.y = 0;
  1060         if (renderer->window) {
  1061             SDL_GetWindowSize(renderer->window,
  1062                               &renderer->viewport.w, &renderer->viewport.h);
  1063         } else {
  1064             /* This will be filled in by UpdateViewport() */
  1065             renderer->viewport.w = 0;
  1066             renderer->viewport.h = 0;
  1067         }
  1068     }
  1069     return renderer->UpdateViewport(renderer);
  1070 }
  1071 
  1072 void
  1073 SDL_RenderGetViewport(SDL_Renderer * renderer, SDL_Rect * rect)
  1074 {
  1075     CHECK_RENDERER_MAGIC(renderer, );
  1076 
  1077     if (rect) {
  1078         rect->x = (int)(renderer->viewport.x / renderer->scale.x);
  1079         rect->y = (int)(renderer->viewport.y / renderer->scale.y);
  1080         rect->w = (int)(renderer->viewport.w / renderer->scale.x);
  1081         rect->h = (int)(renderer->viewport.h / renderer->scale.y);
  1082     }
  1083 }
  1084 
  1085 int
  1086 SDL_RenderSetScale(SDL_Renderer * renderer, float scaleX, float scaleY)
  1087 {
  1088     CHECK_RENDERER_MAGIC(renderer, -1);
  1089 
  1090     renderer->scale.x = scaleX;
  1091     renderer->scale.y = scaleY;
  1092     return 0;
  1093 }
  1094 
  1095 void
  1096 SDL_RenderGetScale(SDL_Renderer * renderer, float *scaleX, float *scaleY)
  1097 {
  1098     CHECK_RENDERER_MAGIC(renderer, );
  1099 
  1100     if (scaleX) {
  1101         *scaleX = renderer->scale.x;
  1102     }
  1103     if (scaleY) {
  1104         *scaleY = renderer->scale.y;
  1105     }
  1106 }
  1107 
  1108 int
  1109 SDL_SetRenderDrawColor(SDL_Renderer * renderer,
  1110                        Uint8 r, Uint8 g, Uint8 b, Uint8 a)
  1111 {
  1112     CHECK_RENDERER_MAGIC(renderer, -1);
  1113 
  1114     renderer->r = r;
  1115     renderer->g = g;
  1116     renderer->b = b;
  1117     renderer->a = a;
  1118     return 0;
  1119 }
  1120 
  1121 int
  1122 SDL_GetRenderDrawColor(SDL_Renderer * renderer,
  1123                        Uint8 * r, Uint8 * g, Uint8 * b, Uint8 * a)
  1124 {
  1125     CHECK_RENDERER_MAGIC(renderer, -1);
  1126 
  1127     if (r) {
  1128         *r = renderer->r;
  1129     }
  1130     if (g) {
  1131         *g = renderer->g;
  1132     }
  1133     if (b) {
  1134         *b = renderer->b;
  1135     }
  1136     if (a) {
  1137         *a = renderer->a;
  1138     }
  1139     return 0;
  1140 }
  1141 
  1142 int
  1143 SDL_SetRenderDrawBlendMode(SDL_Renderer * renderer, SDL_BlendMode blendMode)
  1144 {
  1145     CHECK_RENDERER_MAGIC(renderer, -1);
  1146 
  1147     renderer->blendMode = blendMode;
  1148     return 0;
  1149 }
  1150 
  1151 int
  1152 SDL_GetRenderDrawBlendMode(SDL_Renderer * renderer, SDL_BlendMode *blendMode)
  1153 {
  1154     CHECK_RENDERER_MAGIC(renderer, -1);
  1155 
  1156     *blendMode = renderer->blendMode;
  1157     return 0;
  1158 }
  1159 
  1160 int
  1161 SDL_RenderClear(SDL_Renderer * renderer)
  1162 {
  1163     CHECK_RENDERER_MAGIC(renderer, -1);
  1164 
  1165     /* Don't draw while we're hidden */
  1166     if (renderer->hidden) {
  1167         return 0;
  1168     }
  1169     return renderer->RenderClear(renderer);
  1170 }
  1171 
  1172 int
  1173 SDL_RenderDrawPoint(SDL_Renderer * renderer, int x, int y)
  1174 {
  1175     SDL_Point point;
  1176 
  1177     point.x = x;
  1178     point.y = y;
  1179     return SDL_RenderDrawPoints(renderer, &point, 1);
  1180 }
  1181 
  1182 static int
  1183 RenderDrawPointsWithRects(SDL_Renderer * renderer,
  1184                      const SDL_Point * points, int count)
  1185 {
  1186     SDL_FRect *frects;
  1187     int i;
  1188     int status;
  1189 
  1190     frects = SDL_stack_alloc(SDL_FRect, count);
  1191     if (!frects) {
  1192         SDL_OutOfMemory();
  1193         return -1;
  1194     }
  1195     for (i = 0; i < count; ++i) {
  1196         frects[i].x = points[i].x * renderer->scale.x;
  1197         frects[i].y = points[i].y * renderer->scale.y;
  1198         frects[i].w = renderer->scale.x;
  1199         frects[i].h = renderer->scale.y;
  1200     }
  1201 
  1202     status = renderer->RenderFillRects(renderer, frects, count);
  1203 
  1204     SDL_stack_free(frects);
  1205 
  1206     return status;
  1207 }
  1208 
  1209 int
  1210 SDL_RenderDrawPoints(SDL_Renderer * renderer,
  1211                      const SDL_Point * points, int count)
  1212 {
  1213     SDL_FPoint *fpoints;
  1214     int i;
  1215     int status;
  1216 
  1217     CHECK_RENDERER_MAGIC(renderer, -1);
  1218 
  1219     if (!points) {
  1220         SDL_SetError("SDL_RenderDrawPoints(): Passed NULL points");
  1221         return -1;
  1222     }
  1223     if (count < 1) {
  1224         return 0;
  1225     }
  1226     /* Don't draw while we're hidden */
  1227     if (renderer->hidden) {
  1228         return 0;
  1229     }
  1230 
  1231     if (renderer->scale.x != 1.0f || renderer->scale.y != 1.0f) {
  1232         return RenderDrawPointsWithRects(renderer, points, count);
  1233     }
  1234 
  1235     fpoints = SDL_stack_alloc(SDL_FPoint, count);
  1236     if (!fpoints) {
  1237         SDL_OutOfMemory();
  1238         return -1;
  1239     }
  1240     for (i = 0; i < count; ++i) {
  1241         fpoints[i].x = points[i].x * renderer->scale.x;
  1242         fpoints[i].y = points[i].y * renderer->scale.y;
  1243     }
  1244 
  1245     status = renderer->RenderDrawPoints(renderer, fpoints, count);
  1246 
  1247     SDL_stack_free(fpoints);
  1248 
  1249     return status;
  1250 }
  1251 
  1252 int
  1253 SDL_RenderDrawLine(SDL_Renderer * renderer, int x1, int y1, int x2, int y2)
  1254 {
  1255     SDL_Point points[2];
  1256 
  1257     points[0].x = x1;
  1258     points[0].y = y1;
  1259     points[1].x = x2;
  1260     points[1].y = y2;
  1261     return SDL_RenderDrawLines(renderer, points, 2);
  1262 }
  1263 
  1264 static int
  1265 RenderDrawLinesWithRects(SDL_Renderer * renderer,
  1266                      const SDL_Point * points, int count)
  1267 {
  1268     SDL_FRect *frect;
  1269     SDL_FRect *frects;
  1270     SDL_FPoint fpoints[2];
  1271     int i, nrects;
  1272     int status;
  1273 
  1274     frects = SDL_stack_alloc(SDL_FRect, count-1);
  1275     if (!frects) {
  1276         SDL_OutOfMemory();
  1277         return -1;
  1278     }
  1279 
  1280     status = 0;
  1281     nrects = 0;
  1282     for (i = 0; i < count-1; ++i) {
  1283         if (points[i].x == points[i+1].x) {
  1284             int minY = SDL_min(points[i].y, points[i+1].y);
  1285             int maxY = SDL_max(points[i].y, points[i+1].y);
  1286 
  1287             frect = &frects[nrects++];
  1288             frect->x = points[i].x * renderer->scale.x;
  1289             frect->y = minY * renderer->scale.y;
  1290             frect->w = renderer->scale.x;
  1291             frect->h = (maxY - minY + 1) * renderer->scale.y;
  1292         } else if (points[i].y == points[i+1].y) {
  1293             int minX = SDL_min(points[i].x, points[i+1].x);
  1294             int maxX = SDL_max(points[i].x, points[i+1].x);
  1295 
  1296             frect = &frects[nrects++];
  1297             frect->x = minX * renderer->scale.x;
  1298             frect->y = points[i].y * renderer->scale.y;
  1299             frect->w = (maxX - minX + 1) * renderer->scale.x;
  1300             frect->h = renderer->scale.y;
  1301         } else {
  1302             /* FIXME: We can't use a rect for this line... */
  1303             frects[0].x = points[i].x * renderer->scale.x;
  1304             frects[0].y = points[i].y * renderer->scale.y;
  1305             frects[1].x = points[i+1].x * renderer->scale.x;
  1306             frects[1].y = points[i+1].y * renderer->scale.y;
  1307             status += renderer->RenderDrawLines(renderer, fpoints, 2);
  1308         }
  1309     }
  1310 
  1311     status += renderer->RenderFillRects(renderer, frects, nrects);
  1312 
  1313     SDL_stack_free(frects);
  1314 
  1315     if (status < 0) {
  1316         status = -1;
  1317     }
  1318     return status;
  1319 }
  1320 
  1321 int
  1322 SDL_RenderDrawLines(SDL_Renderer * renderer,
  1323                     const SDL_Point * points, int count)
  1324 {
  1325     SDL_FPoint *fpoints;
  1326     int i;
  1327     int status;
  1328 
  1329     CHECK_RENDERER_MAGIC(renderer, -1);
  1330 
  1331     if (!points) {
  1332         SDL_SetError("SDL_RenderDrawLines(): Passed NULL points");
  1333         return -1;
  1334     }
  1335     if (count < 2) {
  1336         return 0;
  1337     }
  1338     /* Don't draw while we're hidden */
  1339     if (renderer->hidden) {
  1340         return 0;
  1341     }
  1342 
  1343     if (renderer->scale.x != 1.0f || renderer->scale.y != 1.0f) {
  1344         return RenderDrawLinesWithRects(renderer, points, count);
  1345     }
  1346 
  1347     fpoints = SDL_stack_alloc(SDL_FPoint, count);
  1348     if (!fpoints) {
  1349         SDL_OutOfMemory();
  1350         return -1;
  1351     }
  1352     for (i = 0; i < count; ++i) {
  1353         fpoints[i].x = points[i].x * renderer->scale.x;
  1354         fpoints[i].y = points[i].y * renderer->scale.y;
  1355     }
  1356 
  1357     status = renderer->RenderDrawLines(renderer, fpoints, count);
  1358 
  1359     SDL_stack_free(fpoints);
  1360 
  1361     return status;
  1362 }
  1363 
  1364 int
  1365 SDL_RenderDrawRect(SDL_Renderer * renderer, const SDL_Rect * rect)
  1366 {
  1367     SDL_Rect full_rect;
  1368     SDL_Point points[5];
  1369 
  1370     CHECK_RENDERER_MAGIC(renderer, -1);
  1371 
  1372     /* If 'rect' == NULL, then outline the whole surface */
  1373     if (!rect) {
  1374         SDL_RenderGetViewport(renderer, &full_rect);
  1375         full_rect.x = 0;
  1376         full_rect.y = 0;
  1377         rect = &full_rect;
  1378     }
  1379 
  1380     points[0].x = rect->x;
  1381     points[0].y = rect->y;
  1382     points[1].x = rect->x+rect->w-1;
  1383     points[1].y = rect->y;
  1384     points[2].x = rect->x+rect->w-1;
  1385     points[2].y = rect->y+rect->h-1;
  1386     points[3].x = rect->x;
  1387     points[3].y = rect->y+rect->h-1;
  1388     points[4].x = rect->x;
  1389     points[4].y = rect->y;
  1390     return SDL_RenderDrawLines(renderer, points, 5);
  1391 }
  1392 
  1393 int
  1394 SDL_RenderDrawRects(SDL_Renderer * renderer,
  1395                     const SDL_Rect * rects, int count)
  1396 {
  1397     int i;
  1398 
  1399     CHECK_RENDERER_MAGIC(renderer, -1);
  1400 
  1401     if (!rects) {
  1402         SDL_SetError("SDL_RenderDrawRects(): Passed NULL rects");
  1403         return -1;
  1404     }
  1405     if (count < 1) {
  1406         return 0;
  1407     }
  1408 
  1409     /* Don't draw while we're hidden */
  1410     if (renderer->hidden) {
  1411         return 0;
  1412     }
  1413     for (i = 0; i < count; ++i) {
  1414         if (SDL_RenderDrawRect(renderer, &rects[i]) < 0) {
  1415             return -1;
  1416         }
  1417     }
  1418     return 0;
  1419 }
  1420 
  1421 int
  1422 SDL_RenderFillRect(SDL_Renderer * renderer, const SDL_Rect * rect)
  1423 {
  1424     SDL_Rect full_rect;
  1425 
  1426     CHECK_RENDERER_MAGIC(renderer, -1);
  1427 
  1428     /* If 'rect' == NULL, then outline the whole surface */
  1429     if (!rect) {
  1430         SDL_RenderGetViewport(renderer, &full_rect);
  1431         full_rect.x = 0;
  1432         full_rect.y = 0;
  1433         rect = &full_rect;
  1434     }
  1435     return SDL_RenderFillRects(renderer, rect, 1);
  1436 }
  1437 
  1438 int
  1439 SDL_RenderFillRects(SDL_Renderer * renderer,
  1440                     const SDL_Rect * rects, int count)
  1441 {
  1442     SDL_FRect *frects;
  1443     int i;
  1444     int status;
  1445 
  1446     CHECK_RENDERER_MAGIC(renderer, -1);
  1447 
  1448     if (!rects) {
  1449         SDL_SetError("SDL_RenderFillRects(): Passed NULL rects");
  1450         return -1;
  1451     }
  1452     if (count < 1) {
  1453         return 0;
  1454     }
  1455     /* Don't draw while we're hidden */
  1456     if (renderer->hidden) {
  1457         return 0;
  1458     }
  1459 
  1460     frects = SDL_stack_alloc(SDL_FRect, count);
  1461     if (!frects) {
  1462         SDL_OutOfMemory();
  1463         return -1;
  1464     }
  1465     for (i = 0; i < count; ++i) {
  1466         frects[i].x = rects[i].x * renderer->scale.x;
  1467         frects[i].y = rects[i].y * renderer->scale.y;
  1468         frects[i].w = rects[i].w * renderer->scale.x;
  1469         frects[i].h = rects[i].h * renderer->scale.y;
  1470     }
  1471 
  1472     status = renderer->RenderFillRects(renderer, frects, count);
  1473 
  1474     SDL_stack_free(frects);
  1475 
  1476     return status;
  1477 }
  1478 
  1479 int
  1480 SDL_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
  1481                const SDL_Rect * srcrect, const SDL_Rect * dstrect)
  1482 {
  1483     SDL_Rect real_srcrect = { 0, 0, 0, 0 };
  1484     SDL_Rect real_dstrect = { 0, 0, 0, 0 };
  1485     SDL_FRect frect;
  1486 
  1487     CHECK_RENDERER_MAGIC(renderer, -1);
  1488     CHECK_TEXTURE_MAGIC(texture, -1);
  1489 
  1490     if (renderer != texture->renderer) {
  1491         SDL_SetError("Texture was not created with this renderer");
  1492         return -1;
  1493     }
  1494 
  1495     real_srcrect.x = 0;
  1496     real_srcrect.y = 0;
  1497     real_srcrect.w = texture->w;
  1498     real_srcrect.h = texture->h;
  1499     if (srcrect) {
  1500         if (!SDL_IntersectRect(srcrect, &real_srcrect, &real_srcrect)) {
  1501             return 0;
  1502         }
  1503     }
  1504 
  1505     SDL_RenderGetViewport(renderer, &real_dstrect);
  1506     real_dstrect.x = 0;
  1507     real_dstrect.y = 0;
  1508     if (dstrect) {
  1509         if (!SDL_IntersectRect(dstrect, &real_dstrect, &real_dstrect)) {
  1510             return 0;
  1511         }
  1512         /* Clip srcrect by the same amount as dstrect was clipped */
  1513         if (dstrect->w != real_dstrect.w) {
  1514             int deltax = (real_dstrect.x - dstrect->x);
  1515             int deltaw = (real_dstrect.w - dstrect->w);
  1516             real_srcrect.x += (deltax * real_srcrect.w) / dstrect->w;
  1517             real_srcrect.w += (deltaw * real_srcrect.w) / dstrect->w;
  1518         }
  1519         if (dstrect->h != real_dstrect.h) {
  1520             int deltay = (real_dstrect.y - dstrect->y);
  1521             int deltah = (real_dstrect.h - dstrect->h);
  1522             real_srcrect.y += (deltay * real_srcrect.h) / dstrect->h;
  1523             real_srcrect.h += (deltah * real_srcrect.h) / dstrect->h;
  1524         }
  1525     }
  1526 
  1527     if (texture->native) {
  1528         texture = texture->native;
  1529     }
  1530 
  1531     /* Don't draw while we're hidden */
  1532     if (renderer->hidden) {
  1533         return 0;
  1534     }
  1535 
  1536     frect.x = real_dstrect.x * renderer->scale.x;
  1537     frect.y = real_dstrect.y * renderer->scale.y;
  1538     frect.w = real_dstrect.w * renderer->scale.x;
  1539     frect.h = real_dstrect.h * renderer->scale.y;
  1540 
  1541     return renderer->RenderCopy(renderer, texture, &real_srcrect, &frect);
  1542 }
  1543 
  1544 
  1545 int
  1546 SDL_RenderCopyEx(SDL_Renderer * renderer, SDL_Texture * texture,
  1547                const SDL_Rect * srcrect, const SDL_Rect * dstrect,
  1548                const double angle, const SDL_Point *center, const SDL_RendererFlip flip)
  1549 {
  1550     SDL_Rect real_srcrect = { 0, 0, 0, 0 };
  1551     SDL_Rect real_dstrect = { 0, 0, 0, 0 };
  1552     SDL_Point real_center;
  1553     SDL_FRect frect;
  1554     SDL_FPoint fcenter;
  1555 
  1556     CHECK_RENDERER_MAGIC(renderer, -1);
  1557     CHECK_TEXTURE_MAGIC(texture, -1);
  1558 
  1559     if (renderer != texture->renderer) {
  1560         SDL_SetError("Texture was not created with this renderer");
  1561         return -1;
  1562     }
  1563     if (!renderer->RenderCopyEx) {
  1564         SDL_SetError("Renderer does not support RenderCopyEx");
  1565         return -1;
  1566     }
  1567     
  1568     real_srcrect.x = 0;
  1569     real_srcrect.y = 0;
  1570     real_srcrect.w = texture->w;
  1571     real_srcrect.h = texture->h;
  1572     if (srcrect) {
  1573         if (!SDL_IntersectRect(srcrect, &real_srcrect, &real_srcrect)) {
  1574             return 0;
  1575         }
  1576     }
  1577 
  1578     /* We don't intersect the dstrect with the viewport as RenderCopy does because of potential rotation clipping issues... TODO: should we? */
  1579     if (dstrect) {
  1580         real_dstrect = *dstrect;
  1581     } else {
  1582         SDL_RenderGetViewport(renderer, &real_dstrect);
  1583         real_dstrect.x = 0;
  1584         real_dstrect.y = 0;
  1585     }
  1586 
  1587     if (texture->native) {
  1588         texture = texture->native;
  1589     }
  1590 
  1591     if(center) real_center = *center;
  1592     else {
  1593         real_center.x = real_dstrect.w/2;
  1594         real_center.y = real_dstrect.h/2;
  1595     }
  1596 
  1597     frect.x = real_dstrect.x * renderer->scale.x;
  1598     frect.y = real_dstrect.y * renderer->scale.y;
  1599     frect.w = real_dstrect.w * renderer->scale.x;
  1600     frect.h = real_dstrect.h * renderer->scale.y;
  1601 
  1602     fcenter.x = real_center.x * renderer->scale.x;
  1603     fcenter.y = real_center.y * renderer->scale.y;
  1604 
  1605     return renderer->RenderCopyEx(renderer, texture, &real_srcrect, &frect, angle, &fcenter, flip);
  1606 }
  1607 
  1608 int
  1609 SDL_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
  1610                      Uint32 format, void * pixels, int pitch)
  1611 {
  1612     SDL_Rect real_rect;
  1613 
  1614     CHECK_RENDERER_MAGIC(renderer, -1);
  1615 
  1616     if (!renderer->RenderReadPixels) {
  1617         SDL_Unsupported();
  1618         return -1;
  1619     }
  1620 
  1621     if (!format) {
  1622         format = SDL_GetWindowPixelFormat(renderer->window);
  1623     }
  1624 
  1625     real_rect.x = renderer->viewport.x;
  1626     real_rect.y = renderer->viewport.y;
  1627     real_rect.w = renderer->viewport.w;
  1628     real_rect.h = renderer->viewport.h;
  1629     if (rect) {
  1630         if (!SDL_IntersectRect(rect, &real_rect, &real_rect)) {
  1631             return 0;
  1632         }
  1633         if (real_rect.y > rect->y) {
  1634             pixels = (Uint8 *)pixels + pitch * (real_rect.y - rect->y);
  1635         }
  1636         if (real_rect.x > rect->x) {
  1637             int bpp = SDL_BYTESPERPIXEL(format);
  1638             pixels = (Uint8 *)pixels + bpp * (real_rect.x - rect->x);
  1639         }
  1640     }
  1641 
  1642     return renderer->RenderReadPixels(renderer, &real_rect,
  1643                                       format, pixels, pitch);
  1644 }
  1645 
  1646 void
  1647 SDL_RenderPresent(SDL_Renderer * renderer)
  1648 {
  1649     CHECK_RENDERER_MAGIC(renderer, );
  1650 
  1651     /* Don't draw while we're hidden */
  1652     if (renderer->hidden) {
  1653         return;
  1654     }
  1655     renderer->RenderPresent(renderer);
  1656 }
  1657 
  1658 void
  1659 SDL_DestroyTexture(SDL_Texture * texture)
  1660 {
  1661     SDL_Renderer *renderer;
  1662 
  1663     CHECK_TEXTURE_MAGIC(texture, );
  1664     texture->magic = NULL;
  1665 
  1666     renderer = texture->renderer;
  1667     if (texture->next) {
  1668         texture->next->prev = texture->prev;
  1669     }
  1670     if (texture->prev) {
  1671         texture->prev->next = texture->next;
  1672     } else {
  1673         renderer->textures = texture->next;
  1674     }
  1675 
  1676     if (texture->native) {
  1677         SDL_DestroyTexture(texture->native);
  1678     }
  1679     if (texture->yuv) {
  1680         SDL_SW_DestroyYUVTexture(texture->yuv);
  1681     }
  1682     if (texture->pixels) {
  1683         SDL_free(texture->pixels);
  1684     }
  1685 
  1686     renderer->DestroyTexture(renderer, texture);
  1687     SDL_free(texture);
  1688 }
  1689 
  1690 void
  1691 SDL_DestroyRenderer(SDL_Renderer * renderer)
  1692 {
  1693     CHECK_RENDERER_MAGIC(renderer, );
  1694 
  1695     SDL_DelEventWatch(SDL_RendererEventWatch, renderer);
  1696 
  1697     /* Free existing textures for this renderer */
  1698     while (renderer->textures) {
  1699         SDL_DestroyTexture(renderer->textures);
  1700     }
  1701 
  1702     if (renderer->window) {
  1703         SDL_SetWindowData(renderer->window, SDL_WINDOWRENDERDATA, NULL);
  1704     }
  1705 
  1706     /* It's no longer magical... */
  1707     renderer->magic = NULL;
  1708 
  1709     /* Free the renderer instance */
  1710     renderer->DestroyRenderer(renderer);
  1711 }
  1712 
  1713 int SDL_GL_BindTexture(SDL_Texture *texture, float *texw, float *texh)
  1714 {
  1715     SDL_Renderer *renderer;
  1716 
  1717     CHECK_TEXTURE_MAGIC(texture, -1);
  1718     renderer = texture->renderer;
  1719     if (renderer && renderer->GL_BindTexture) {
  1720         return renderer->GL_BindTexture(renderer, texture, texw, texh);
  1721     }
  1722 
  1723     SDL_Unsupported();
  1724     return -1;
  1725 }
  1726 
  1727 int SDL_GL_UnbindTexture(SDL_Texture *texture)
  1728 {
  1729     SDL_Renderer *renderer;
  1730 
  1731     CHECK_TEXTURE_MAGIC(texture, -1);
  1732     renderer = texture->renderer;
  1733     if (renderer && renderer->GL_UnbindTexture) {
  1734         return renderer->GL_UnbindTexture(renderer, texture);
  1735     }
  1736 
  1737     SDL_Unsupported();
  1738     return -1;
  1739 }
  1740 
  1741 /* vi: set ts=4 sw=4 expandtab: */