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