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