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