src/render/SDL_render.c
author Edward Rudd <urkle@outoforder.cc>
Fri, 20 Sep 2013 13:43:00 -0400
changeset 7746 6a05d7352575
parent 7719 31b5f9ff36ca
child 7759 869583422e5a
permissions -rw-r--r--
add in High DPI support (aka Retina)

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