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