src/render/SDL_render.c
author Sam Lantinga
Fri, 27 Jan 2017 21:23:27 -0800
changeset 10861 71d8f9afb690
parent 10775 d8a4f8a929b2
child 10926 97c829825e0e
permissions -rw-r--r--
Fixed bug 3569 - GL_UpdateViewport leaves PROJECTION matrix selected

Tom Seddon

GL_ActivateRenderer may call GL_UpdateViewport, which leaves the GL_PROJECTION matrix selected. But after GL_ResetState, the GL_MODELVIEW matrix is selected, suggesting that's the intended default state.

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