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