src/render/SDL_render.c
author Ryan C. Gordon <icculus@icculus.org>
Thu, 09 Apr 2015 22:28:37 -0400
changeset 9541 cf8fab52e33b
parent 9084 a8cbb653aea4
child 9619 b94b6d0bff0f
child 11072 4d8984d051a2
permissions -rw-r--r--
Merged Alex Szpakowski's iOS-improvement branch to default.

Fixes Bugzilla #2798.
Fixes Bugzilla #2212.
Fixes Bugzilla #2826.
Fixes Bugzilla #2661.
Fixes Bugzilla #1885.
Fixes Bugzilla #1578.
Fixes Bugzilla #2751.

(whew!)

Notable changes, from Alex's notes:

- The SDL_WINDOW_ALLOW_HIGHDPI flag is now needed (along with SDL_GL_GetDrawableSize or SDL_GetRendererOutputSize) to use Retina / high DPI resolutions, bringing SDL’s Retina-related behavior on iOS in line with Mac OS X. Window dimensions and display modes are now in the “points” (non-high DPI) coordinate system rather than pixels, whereas SDL_GL_GetDrawableSize is in pixels.

- Reworked the custom extended launch screen code:
- It now hides after the first SDL_PumpEvents call rather than SDL_CreateWindow, and it fades out in a similar manner to the system launch screen behavior.
- It now mirrors the system launch screen behavior when deciding which image to display: it falls back to using the Launch Images dictionary in Info.plist if the iOS 8+ launch screen nib isn’t available, and if the Launch Images dictionary doesn’t exist it uses the old standard launch image names.
- The extended launch screen can now be disabled via the SDL_IPHONE_LAUNCHSCREEN define in SDL_config_iphoneos.h.

- Added support for SDL_HINT_ACCELEROMETER_AS_JOYSTICK.

- Added access to a window view's renderbuffer and framebuffer to syswm.

- Added OpenGL ES debug labels for the Renderbuffer and Framebuffer Objects created with SDL_GL_CreateContext.

- Added support for sRGB OpenGL ES contexts on iOS 7+.

- Updated OpenGL ES contexts to support native-resolution rendering (when SDL_WINDOW_ALLOW_HIGHDPI is enabled) on the iPhone 6 Plus, i.e. 1080x1920 rather than 1242x2208.

- Updated SDL_GL_CreateContext, SDL_GL_SwapWindow, SDL_GL_MakeCurrent, and SDL_GL_DeleteContext to be more robust.

- Updated SDL windows to display a UIView at all times, even when an OpenGL context is not active. This allows rotation, touch events, and other windowing-related events to work properly without an active OpenGL context. It also makes it easier to use SDL_GetWindowWMInfo after creating a SDL window.

- Updated the iOS-specific Objective-C code to use cleaner and more modern language features and APIs, including ARC instead of manual reference counting.

- Updated SDL_HINT_ORIENTATIONS to allow disabling custom orientations if the hint is set with no valid orientation names.

- Fixed several rotation and orientation bugs with windows and display modes, especially in iOS 8+.

- Fixed SDL_SetWindowFullscreen failing to update the status bar visibility on iOS 7+.

- Fixed the orientation of the offset applied to the window’s view when the onscreen keyboard is shown in iOS 8+.

- Fixed SDL_IsScreenKeyboardShown (patch by Phil Hassey.)

- Fixed several major memory leaks caused by missing autorelease pool blocks in the iOS-specific Objective-C code.

- Removed several dead code paths.

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