src/render/SDL_render.c
author Sam Lantinga <slouken@libsdl.org>
Sat, 28 Sep 2013 14:06:47 -0700
changeset 7759 869583422e5a
parent 7746 6a05d7352575
child 7760 63b519624589
permissions -rw-r--r--
Added optimized YUV texture upload path with SDL_UpdateYUVTexture()
     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_UpdateTextureYUVPlanar(SDL_Texture * texture, const SDL_Rect * rect,
   809                            const Uint8 *Yplane, int Ypitch,
   810                            const Uint8 *Uplane, int Upitch,
   811                            const Uint8 *Vplane, int Vpitch)
   812 {
   813     SDL_Texture *native = texture->native;
   814     SDL_Rect full_rect;
   815 
   816     if (SDL_SW_UpdateYUVTexturePlanar(texture->yuv, rect, Yplane, Ypitch, Uplane, Upitch, Vplane, Vpitch) < 0) {
   817         return -1;
   818     }
   819 
   820     full_rect.x = 0;
   821     full_rect.y = 0;
   822     full_rect.w = texture->w;
   823     full_rect.h = texture->h;
   824     rect = &full_rect;
   825 
   826     if (texture->access == SDL_TEXTUREACCESS_STREAMING) {
   827         /* We can lock the texture and copy to it */
   828         void *native_pixels;
   829         int native_pitch;
   830 
   831         if (SDL_LockTexture(native, rect, &native_pixels, &native_pitch) < 0) {
   832             return -1;
   833         }
   834         SDL_SW_CopyYUVToRGB(texture->yuv, rect, native->format,
   835                             rect->w, rect->h, native_pixels, native_pitch);
   836         SDL_UnlockTexture(native);
   837     } else {
   838         /* Use a temporary buffer for updating */
   839         void *temp_pixels;
   840         int temp_pitch;
   841 
   842         temp_pitch = (((rect->w * SDL_BYTESPERPIXEL(native->format)) + 3) & ~3);
   843         temp_pixels = SDL_malloc(rect->h * temp_pitch);
   844         if (!temp_pixels) {
   845             return SDL_OutOfMemory();
   846         }
   847         SDL_SW_CopyYUVToRGB(texture->yuv, rect, native->format,
   848                             rect->w, rect->h, temp_pixels, temp_pitch);
   849         SDL_UpdateTexture(native, rect, temp_pixels, temp_pitch);
   850         SDL_free(temp_pixels);
   851     }
   852     return 0;
   853 }
   854 
   855 int SDL_UpdateYUVTexture(SDL_Texture * texture, const SDL_Rect * rect,
   856                          const Uint8 *Yplane, int Ypitch,
   857                          const Uint8 *Uplane, int Upitch,
   858                          const Uint8 *Vplane, int Vpitch)
   859 {
   860     SDL_Renderer *renderer;
   861     SDL_Rect full_rect;
   862 
   863     CHECK_TEXTURE_MAGIC(texture, -1);
   864 
   865     if (!Yplane) {
   866         return SDL_InvalidParamError("Yplane");
   867     }
   868     if (!Ypitch) {
   869         return SDL_InvalidParamError("Ypitch");
   870     }
   871     if (!Uplane) {
   872         return SDL_InvalidParamError("Uplane");
   873     }
   874     if (!Upitch) {
   875         return SDL_InvalidParamError("Upitch");
   876     }
   877     if (!Vplane) {
   878         return SDL_InvalidParamError("Vplane");
   879     }
   880     if (!Vpitch) {
   881         return SDL_InvalidParamError("Vpitch");
   882     }
   883 
   884     if (texture->format != SDL_PIXELFORMAT_YV12 &&
   885         texture->format != SDL_PIXELFORMAT_IYUV) {
   886         return SDL_SetError("Texture format must by YV12 or IYUV");
   887     }
   888 
   889     if (!rect) {
   890         full_rect.x = 0;
   891         full_rect.y = 0;
   892         full_rect.w = texture->w;
   893         full_rect.h = texture->h;
   894         rect = &full_rect;
   895     }
   896 
   897     if (texture->yuv) {
   898         return SDL_UpdateTextureYUVPlanar(texture, rect, Yplane, Ypitch, Uplane, Upitch, Vplane, Vpitch);
   899     } else {
   900         SDL_assert(!texture->native);
   901         renderer = texture->renderer;
   902         SDL_assert(renderer->UpdateTextureYUV);
   903         return renderer->UpdateTextureYUV(renderer, texture, rect, Yplane, Ypitch, Uplane, Upitch, Vplane, Vpitch);
   904     }
   905 }
   906 
   907 static int
   908 SDL_LockTextureYUV(SDL_Texture * texture, const SDL_Rect * rect,
   909                    void **pixels, int *pitch)
   910 {
   911     return SDL_SW_LockYUVTexture(texture->yuv, rect, pixels, pitch);
   912 }
   913 
   914 static int
   915 SDL_LockTextureNative(SDL_Texture * texture, const SDL_Rect * rect,
   916                       void **pixels, int *pitch)
   917 {
   918     texture->locked_rect = *rect;
   919     *pixels = (void *) ((Uint8 *) texture->pixels +
   920                         rect->y * texture->pitch +
   921                         rect->x * SDL_BYTESPERPIXEL(texture->format));
   922     *pitch = texture->pitch;
   923     return 0;
   924 }
   925 
   926 int
   927 SDL_LockTexture(SDL_Texture * texture, const SDL_Rect * rect,
   928                 void **pixels, int *pitch)
   929 {
   930     SDL_Renderer *renderer;
   931     SDL_Rect full_rect;
   932 
   933     CHECK_TEXTURE_MAGIC(texture, -1);
   934 
   935     if (texture->access != SDL_TEXTUREACCESS_STREAMING) {
   936         return SDL_SetError("SDL_LockTexture(): texture must be streaming");
   937     }
   938 
   939     if (!rect) {
   940         full_rect.x = 0;
   941         full_rect.y = 0;
   942         full_rect.w = texture->w;
   943         full_rect.h = texture->h;
   944         rect = &full_rect;
   945     }
   946 
   947     if (texture->yuv) {
   948         return SDL_LockTextureYUV(texture, rect, pixels, pitch);
   949     } else if (texture->native) {
   950         return SDL_LockTextureNative(texture, rect, pixels, pitch);
   951     } else {
   952         renderer = texture->renderer;
   953         return renderer->LockTexture(renderer, texture, rect, pixels, pitch);
   954     }
   955 }
   956 
   957 static void
   958 SDL_UnlockTextureYUV(SDL_Texture * texture)
   959 {
   960     SDL_Texture *native = texture->native;
   961     void *native_pixels;
   962     int native_pitch;
   963     SDL_Rect rect;
   964 
   965     rect.x = 0;
   966     rect.y = 0;
   967     rect.w = texture->w;
   968     rect.h = texture->h;
   969 
   970     if (SDL_LockTexture(native, &rect, &native_pixels, &native_pitch) < 0) {
   971         return;
   972     }
   973     SDL_SW_CopyYUVToRGB(texture->yuv, &rect, native->format,
   974                         rect.w, rect.h, native_pixels, native_pitch);
   975     SDL_UnlockTexture(native);
   976 }
   977 
   978 static void
   979 SDL_UnlockTextureNative(SDL_Texture * texture)
   980 {
   981     SDL_Texture *native = texture->native;
   982     void *native_pixels;
   983     int native_pitch;
   984     const SDL_Rect *rect = &texture->locked_rect;
   985     const void* pixels = (void *) ((Uint8 *) texture->pixels +
   986                         rect->y * texture->pitch +
   987                         rect->x * SDL_BYTESPERPIXEL(texture->format));
   988     int pitch = texture->pitch;
   989 
   990     if (SDL_LockTexture(native, rect, &native_pixels, &native_pitch) < 0) {
   991         return;
   992     }
   993     SDL_ConvertPixels(rect->w, rect->h,
   994                       texture->format, pixels, pitch,
   995                       native->format, native_pixels, native_pitch);
   996     SDL_UnlockTexture(native);
   997 }
   998 
   999 void
  1000 SDL_UnlockTexture(SDL_Texture * texture)
  1001 {
  1002     SDL_Renderer *renderer;
  1003 
  1004     CHECK_TEXTURE_MAGIC(texture, );
  1005 
  1006     if (texture->access != SDL_TEXTUREACCESS_STREAMING) {
  1007         return;
  1008     }
  1009     if (texture->yuv) {
  1010         SDL_UnlockTextureYUV(texture);
  1011     } else if (texture->native) {
  1012         SDL_UnlockTextureNative(texture);
  1013     } else {
  1014         renderer = texture->renderer;
  1015         renderer->UnlockTexture(renderer, texture);
  1016     }
  1017 }
  1018 
  1019 SDL_bool
  1020 SDL_RenderTargetSupported(SDL_Renderer *renderer)
  1021 {
  1022     if (!renderer || !renderer->SetRenderTarget) {
  1023         return SDL_FALSE;
  1024     }
  1025     return (renderer->info.flags & SDL_RENDERER_TARGETTEXTURE) != 0;
  1026 }
  1027 
  1028 int
  1029 SDL_SetRenderTarget(SDL_Renderer *renderer, SDL_Texture *texture)
  1030 {
  1031     if (!SDL_RenderTargetSupported(renderer)) {
  1032         return SDL_Unsupported();
  1033     }
  1034     if (texture == renderer->target) {
  1035         /* Nothing to do! */
  1036         return 0;
  1037     }
  1038 
  1039     /* texture == NULL is valid and means reset the target to the window */
  1040     if (texture) {
  1041         CHECK_TEXTURE_MAGIC(texture, -1);
  1042         if (renderer != texture->renderer) {
  1043             return SDL_SetError("Texture was not created with this renderer");
  1044         }
  1045         if (texture->access != SDL_TEXTUREACCESS_TARGET) {
  1046             return SDL_SetError("Texture not created with SDL_TEXTUREACCESS_TARGET");
  1047         }
  1048         if (texture->native) {
  1049             /* Always render to the native texture */
  1050             texture = texture->native;
  1051         }
  1052     }
  1053 
  1054     if (texture && !renderer->target) {
  1055         /* Make a backup of the viewport */
  1056         renderer->viewport_backup = renderer->viewport;
  1057         renderer->clip_rect_backup = renderer->clip_rect;
  1058         renderer->scale_backup = renderer->scale;
  1059         renderer->logical_w_backup = renderer->logical_w;
  1060         renderer->logical_h_backup = renderer->logical_h;
  1061     }
  1062     renderer->target = texture;
  1063 
  1064     if (renderer->SetRenderTarget(renderer, texture) < 0) {
  1065         return -1;
  1066     }
  1067 
  1068     if (texture) {
  1069         renderer->viewport.x = 0;
  1070         renderer->viewport.y = 0;
  1071         renderer->viewport.w = texture->w;
  1072         renderer->viewport.h = texture->h;
  1073         renderer->scale.x = 1.0f;
  1074         renderer->scale.y = 1.0f;
  1075         renderer->logical_w = texture->w;
  1076         renderer->logical_h = texture->h;
  1077     } else {
  1078         renderer->viewport = renderer->viewport_backup;
  1079         renderer->clip_rect = renderer->clip_rect_backup;
  1080         renderer->scale = renderer->scale_backup;
  1081         renderer->logical_w = renderer->logical_w_backup;
  1082         renderer->logical_h = renderer->logical_h_backup;
  1083     }
  1084     if (renderer->UpdateViewport(renderer) < 0) {
  1085         return -1;
  1086     }
  1087     if (renderer->UpdateClipRect(renderer) < 0) {
  1088         return -1;
  1089     }
  1090 
  1091     /* All set! */
  1092     return 0;
  1093 }
  1094 
  1095 SDL_Texture *
  1096 SDL_GetRenderTarget(SDL_Renderer *renderer)
  1097 {
  1098     return renderer->target;
  1099 }
  1100 
  1101 static int
  1102 UpdateLogicalSize(SDL_Renderer *renderer)
  1103 {
  1104     int w, h;
  1105     float want_aspect;
  1106     float real_aspect;
  1107     float scale;
  1108     SDL_Rect viewport;
  1109 
  1110     if (SDL_GetRendererOutputSize(renderer, &w, &h) < 0) {
  1111         return -1;
  1112     }
  1113 
  1114     want_aspect = (float)renderer->logical_w / renderer->logical_h;
  1115     real_aspect = (float)w / h;
  1116 
  1117     /* Clear the scale because we're setting viewport in output coordinates */
  1118     SDL_RenderSetScale(renderer, 1.0f, 1.0f);
  1119 
  1120     if (SDL_fabs(want_aspect-real_aspect) < 0.0001) {
  1121         /* The aspect ratios are the same, just scale appropriately */
  1122         scale = (float)w / renderer->logical_w;
  1123         SDL_RenderSetViewport(renderer, NULL);
  1124     } else if (want_aspect > real_aspect) {
  1125         /* We want a wider aspect ratio than is available - letterbox it */
  1126         scale = (float)w / renderer->logical_w;
  1127         viewport.x = 0;
  1128         viewport.w = w;
  1129         viewport.h = (int)SDL_ceil(renderer->logical_h * scale);
  1130         viewport.y = (h - viewport.h) / 2;
  1131         SDL_RenderSetViewport(renderer, &viewport);
  1132     } else {
  1133         /* We want a narrower aspect ratio than is available - use side-bars */
  1134         scale = (float)h / renderer->logical_h;
  1135         viewport.y = 0;
  1136         viewport.h = h;
  1137         viewport.w = (int)SDL_ceil(renderer->logical_w * scale);
  1138         viewport.x = (w - viewport.w) / 2;
  1139         SDL_RenderSetViewport(renderer, &viewport);
  1140     }
  1141 
  1142     /* Set the new scale */
  1143     SDL_RenderSetScale(renderer, scale, scale);
  1144 
  1145     return 0;
  1146 }
  1147 
  1148 int
  1149 SDL_RenderSetLogicalSize(SDL_Renderer * renderer, int w, int h)
  1150 {
  1151     CHECK_RENDERER_MAGIC(renderer, -1);
  1152 
  1153     if (!w || !h) {
  1154         /* Clear any previous logical resolution */
  1155         renderer->logical_w = 0;
  1156         renderer->logical_h = 0;
  1157         SDL_RenderSetViewport(renderer, NULL);
  1158         SDL_RenderSetScale(renderer, 1.0f, 1.0f);
  1159         return 0;
  1160     }
  1161 
  1162     renderer->logical_w = w;
  1163     renderer->logical_h = h;
  1164 
  1165     return UpdateLogicalSize(renderer);
  1166 }
  1167 
  1168 void
  1169 SDL_RenderGetLogicalSize(SDL_Renderer * renderer, int *w, int *h)
  1170 {
  1171     CHECK_RENDERER_MAGIC(renderer, );
  1172 
  1173     if (w) {
  1174         *w = renderer->logical_w;
  1175     }
  1176     if (h) {
  1177         *h = renderer->logical_h;
  1178     }
  1179 }
  1180 
  1181 int
  1182 SDL_RenderSetViewport(SDL_Renderer * renderer, const SDL_Rect * rect)
  1183 {
  1184     CHECK_RENDERER_MAGIC(renderer, -1);
  1185 
  1186     if (rect) {
  1187         renderer->viewport.x = (int)SDL_floor(rect->x * renderer->scale.x);
  1188         renderer->viewport.y = (int)SDL_floor(rect->y * renderer->scale.y);
  1189         renderer->viewport.w = (int)SDL_ceil(rect->w * renderer->scale.x);
  1190         renderer->viewport.h = (int)SDL_ceil(rect->h * renderer->scale.y);
  1191     } else {
  1192         renderer->viewport.x = 0;
  1193         renderer->viewport.y = 0;
  1194         if (SDL_GetRendererOutputSize(renderer, &renderer->viewport.w, &renderer->viewport.h) < 0) {
  1195             return -1;
  1196         }
  1197     }
  1198     return renderer->UpdateViewport(renderer);
  1199 }
  1200 
  1201 void
  1202 SDL_RenderGetViewport(SDL_Renderer * renderer, SDL_Rect * rect)
  1203 {
  1204     CHECK_RENDERER_MAGIC(renderer, );
  1205 
  1206     if (rect) {
  1207         rect->x = (int)(renderer->viewport.x / renderer->scale.x);
  1208         rect->y = (int)(renderer->viewport.y / renderer->scale.y);
  1209         rect->w = (int)(renderer->viewport.w / renderer->scale.x);
  1210         rect->h = (int)(renderer->viewport.h / renderer->scale.y);
  1211     }
  1212 }
  1213 
  1214 int
  1215 SDL_RenderSetClipRect(SDL_Renderer * renderer, const SDL_Rect * rect)
  1216 {
  1217     CHECK_RENDERER_MAGIC(renderer, -1)
  1218 
  1219     if (rect) {
  1220         renderer->clip_rect.x = (int)SDL_floor(rect->x * renderer->scale.x);
  1221         renderer->clip_rect.y = (int)SDL_floor(rect->y * renderer->scale.y);
  1222         renderer->clip_rect.w = (int)SDL_ceil(rect->w * renderer->scale.x);
  1223         renderer->clip_rect.h = (int)SDL_ceil(rect->h * renderer->scale.y);
  1224     } else {
  1225         SDL_zero(renderer->clip_rect);
  1226     }
  1227     return renderer->UpdateClipRect(renderer);
  1228 }
  1229 
  1230 void
  1231 SDL_RenderGetClipRect(SDL_Renderer * renderer, SDL_Rect * rect)
  1232 {
  1233     CHECK_RENDERER_MAGIC(renderer, )
  1234 
  1235     if (rect) {
  1236         rect->x = (int)(renderer->clip_rect.x / renderer->scale.x);
  1237         rect->y = (int)(renderer->clip_rect.y / renderer->scale.y);
  1238         rect->w = (int)(renderer->clip_rect.w / renderer->scale.x);
  1239         rect->h = (int)(renderer->clip_rect.h / renderer->scale.y);
  1240     }
  1241 }
  1242 
  1243 int
  1244 SDL_RenderSetScale(SDL_Renderer * renderer, float scaleX, float scaleY)
  1245 {
  1246     CHECK_RENDERER_MAGIC(renderer, -1);
  1247 
  1248     renderer->scale.x = scaleX;
  1249     renderer->scale.y = scaleY;
  1250     return 0;
  1251 }
  1252 
  1253 void
  1254 SDL_RenderGetScale(SDL_Renderer * renderer, float *scaleX, float *scaleY)
  1255 {
  1256     CHECK_RENDERER_MAGIC(renderer, );
  1257 
  1258     if (scaleX) {
  1259         *scaleX = renderer->scale.x;
  1260     }
  1261     if (scaleY) {
  1262         *scaleY = renderer->scale.y;
  1263     }
  1264 }
  1265 
  1266 int
  1267 SDL_SetRenderDrawColor(SDL_Renderer * renderer,
  1268                        Uint8 r, Uint8 g, Uint8 b, Uint8 a)
  1269 {
  1270     CHECK_RENDERER_MAGIC(renderer, -1);
  1271 
  1272     renderer->r = r;
  1273     renderer->g = g;
  1274     renderer->b = b;
  1275     renderer->a = a;
  1276     return 0;
  1277 }
  1278 
  1279 int
  1280 SDL_GetRenderDrawColor(SDL_Renderer * renderer,
  1281                        Uint8 * r, Uint8 * g, Uint8 * b, Uint8 * a)
  1282 {
  1283     CHECK_RENDERER_MAGIC(renderer, -1);
  1284 
  1285     if (r) {
  1286         *r = renderer->r;
  1287     }
  1288     if (g) {
  1289         *g = renderer->g;
  1290     }
  1291     if (b) {
  1292         *b = renderer->b;
  1293     }
  1294     if (a) {
  1295         *a = renderer->a;
  1296     }
  1297     return 0;
  1298 }
  1299 
  1300 int
  1301 SDL_SetRenderDrawBlendMode(SDL_Renderer * renderer, SDL_BlendMode blendMode)
  1302 {
  1303     CHECK_RENDERER_MAGIC(renderer, -1);
  1304 
  1305     renderer->blendMode = blendMode;
  1306     return 0;
  1307 }
  1308 
  1309 int
  1310 SDL_GetRenderDrawBlendMode(SDL_Renderer * renderer, SDL_BlendMode *blendMode)
  1311 {
  1312     CHECK_RENDERER_MAGIC(renderer, -1);
  1313 
  1314     *blendMode = renderer->blendMode;
  1315     return 0;
  1316 }
  1317 
  1318 int
  1319 SDL_RenderClear(SDL_Renderer * renderer)
  1320 {
  1321     CHECK_RENDERER_MAGIC(renderer, -1);
  1322 
  1323     /* Don't draw while we're hidden */
  1324     if (renderer->hidden) {
  1325         return 0;
  1326     }
  1327     return renderer->RenderClear(renderer);
  1328 }
  1329 
  1330 int
  1331 SDL_RenderDrawPoint(SDL_Renderer * renderer, int x, int y)
  1332 {
  1333     SDL_Point point;
  1334 
  1335     point.x = x;
  1336     point.y = y;
  1337     return SDL_RenderDrawPoints(renderer, &point, 1);
  1338 }
  1339 
  1340 static int
  1341 RenderDrawPointsWithRects(SDL_Renderer * renderer,
  1342                      const SDL_Point * points, int count)
  1343 {
  1344     SDL_FRect *frects;
  1345     int i;
  1346     int status;
  1347 
  1348     frects = SDL_stack_alloc(SDL_FRect, count);
  1349     if (!frects) {
  1350         return SDL_OutOfMemory();
  1351     }
  1352     for (i = 0; i < count; ++i) {
  1353         frects[i].x = points[i].x * renderer->scale.x;
  1354         frects[i].y = points[i].y * renderer->scale.y;
  1355         frects[i].w = renderer->scale.x;
  1356         frects[i].h = renderer->scale.y;
  1357     }
  1358 
  1359     status = renderer->RenderFillRects(renderer, frects, count);
  1360 
  1361     SDL_stack_free(frects);
  1362 
  1363     return status;
  1364 }
  1365 
  1366 int
  1367 SDL_RenderDrawPoints(SDL_Renderer * renderer,
  1368                      const SDL_Point * points, int count)
  1369 {
  1370     SDL_FPoint *fpoints;
  1371     int i;
  1372     int status;
  1373 
  1374     CHECK_RENDERER_MAGIC(renderer, -1);
  1375 
  1376     if (!points) {
  1377         return SDL_SetError("SDL_RenderDrawPoints(): Passed NULL points");
  1378     }
  1379     if (count < 1) {
  1380         return 0;
  1381     }
  1382     /* Don't draw while we're hidden */
  1383     if (renderer->hidden) {
  1384         return 0;
  1385     }
  1386 
  1387     if (renderer->scale.x != 1.0f || renderer->scale.y != 1.0f) {
  1388         return RenderDrawPointsWithRects(renderer, points, count);
  1389     }
  1390 
  1391     fpoints = SDL_stack_alloc(SDL_FPoint, count);
  1392     if (!fpoints) {
  1393         return SDL_OutOfMemory();
  1394     }
  1395     for (i = 0; i < count; ++i) {
  1396         fpoints[i].x = points[i].x * renderer->scale.x;
  1397         fpoints[i].y = points[i].y * renderer->scale.y;
  1398     }
  1399 
  1400     status = renderer->RenderDrawPoints(renderer, fpoints, count);
  1401 
  1402     SDL_stack_free(fpoints);
  1403 
  1404     return status;
  1405 }
  1406 
  1407 int
  1408 SDL_RenderDrawLine(SDL_Renderer * renderer, int x1, int y1, int x2, int y2)
  1409 {
  1410     SDL_Point points[2];
  1411 
  1412     points[0].x = x1;
  1413     points[0].y = y1;
  1414     points[1].x = x2;
  1415     points[1].y = y2;
  1416     return SDL_RenderDrawLines(renderer, points, 2);
  1417 }
  1418 
  1419 static int
  1420 RenderDrawLinesWithRects(SDL_Renderer * renderer,
  1421                      const SDL_Point * points, int count)
  1422 {
  1423     SDL_FRect *frect;
  1424     SDL_FRect *frects;
  1425     SDL_FPoint fpoints[2];
  1426     int i, nrects;
  1427     int status;
  1428 
  1429     frects = SDL_stack_alloc(SDL_FRect, count-1);
  1430     if (!frects) {
  1431         return SDL_OutOfMemory();
  1432     }
  1433 
  1434     status = 0;
  1435     nrects = 0;
  1436     for (i = 0; i < count-1; ++i) {
  1437         if (points[i].x == points[i+1].x) {
  1438             int minY = SDL_min(points[i].y, points[i+1].y);
  1439             int maxY = SDL_max(points[i].y, points[i+1].y);
  1440 
  1441             frect = &frects[nrects++];
  1442             frect->x = points[i].x * renderer->scale.x;
  1443             frect->y = minY * renderer->scale.y;
  1444             frect->w = renderer->scale.x;
  1445             frect->h = (maxY - minY + 1) * renderer->scale.y;
  1446         } else if (points[i].y == points[i+1].y) {
  1447             int minX = SDL_min(points[i].x, points[i+1].x);
  1448             int maxX = SDL_max(points[i].x, points[i+1].x);
  1449 
  1450             frect = &frects[nrects++];
  1451             frect->x = minX * renderer->scale.x;
  1452             frect->y = points[i].y * renderer->scale.y;
  1453             frect->w = (maxX - minX + 1) * renderer->scale.x;
  1454             frect->h = renderer->scale.y;
  1455         } else {
  1456             /* FIXME: We can't use a rect for this line... */
  1457             fpoints[0].x = points[i].x * renderer->scale.x;
  1458             fpoints[0].y = points[i].y * renderer->scale.y;
  1459             fpoints[1].x = points[i+1].x * renderer->scale.x;
  1460             fpoints[1].y = points[i+1].y * renderer->scale.y;
  1461             status += renderer->RenderDrawLines(renderer, fpoints, 2);
  1462         }
  1463     }
  1464 
  1465     status += renderer->RenderFillRects(renderer, frects, nrects);
  1466 
  1467     SDL_stack_free(frects);
  1468 
  1469     if (status < 0) {
  1470         status = -1;
  1471     }
  1472     return status;
  1473 }
  1474 
  1475 int
  1476 SDL_RenderDrawLines(SDL_Renderer * renderer,
  1477                     const SDL_Point * points, int count)
  1478 {
  1479     SDL_FPoint *fpoints;
  1480     int i;
  1481     int status;
  1482 
  1483     CHECK_RENDERER_MAGIC(renderer, -1);
  1484 
  1485     if (!points) {
  1486         return SDL_SetError("SDL_RenderDrawLines(): Passed NULL points");
  1487     }
  1488     if (count < 2) {
  1489         return 0;
  1490     }
  1491     /* Don't draw while we're hidden */
  1492     if (renderer->hidden) {
  1493         return 0;
  1494     }
  1495 
  1496     if (renderer->scale.x != 1.0f || renderer->scale.y != 1.0f) {
  1497         return RenderDrawLinesWithRects(renderer, points, count);
  1498     }
  1499 
  1500     fpoints = SDL_stack_alloc(SDL_FPoint, count);
  1501     if (!fpoints) {
  1502         return SDL_OutOfMemory();
  1503     }
  1504     for (i = 0; i < count; ++i) {
  1505         fpoints[i].x = points[i].x * renderer->scale.x;
  1506         fpoints[i].y = points[i].y * renderer->scale.y;
  1507     }
  1508 
  1509     status = renderer->RenderDrawLines(renderer, fpoints, count);
  1510 
  1511     SDL_stack_free(fpoints);
  1512 
  1513     return status;
  1514 }
  1515 
  1516 int
  1517 SDL_RenderDrawRect(SDL_Renderer * renderer, const SDL_Rect * rect)
  1518 {
  1519     SDL_Rect full_rect;
  1520     SDL_Point points[5];
  1521 
  1522     CHECK_RENDERER_MAGIC(renderer, -1);
  1523 
  1524     /* If 'rect' == NULL, then outline the whole surface */
  1525     if (!rect) {
  1526         SDL_RenderGetViewport(renderer, &full_rect);
  1527         full_rect.x = 0;
  1528         full_rect.y = 0;
  1529         rect = &full_rect;
  1530     }
  1531 
  1532     points[0].x = rect->x;
  1533     points[0].y = rect->y;
  1534     points[1].x = rect->x+rect->w-1;
  1535     points[1].y = rect->y;
  1536     points[2].x = rect->x+rect->w-1;
  1537     points[2].y = rect->y+rect->h-1;
  1538     points[3].x = rect->x;
  1539     points[3].y = rect->y+rect->h-1;
  1540     points[4].x = rect->x;
  1541     points[4].y = rect->y;
  1542     return SDL_RenderDrawLines(renderer, points, 5);
  1543 }
  1544 
  1545 int
  1546 SDL_RenderDrawRects(SDL_Renderer * renderer,
  1547                     const SDL_Rect * rects, int count)
  1548 {
  1549     int i;
  1550 
  1551     CHECK_RENDERER_MAGIC(renderer, -1);
  1552 
  1553     if (!rects) {
  1554         return SDL_SetError("SDL_RenderDrawRects(): Passed NULL rects");
  1555     }
  1556     if (count < 1) {
  1557         return 0;
  1558     }
  1559 
  1560     /* Don't draw while we're hidden */
  1561     if (renderer->hidden) {
  1562         return 0;
  1563     }
  1564     for (i = 0; i < count; ++i) {
  1565         if (SDL_RenderDrawRect(renderer, &rects[i]) < 0) {
  1566             return -1;
  1567         }
  1568     }
  1569     return 0;
  1570 }
  1571 
  1572 int
  1573 SDL_RenderFillRect(SDL_Renderer * renderer, const SDL_Rect * rect)
  1574 {
  1575     SDL_Rect full_rect = { 0, 0, 0, 0 };
  1576 
  1577     CHECK_RENDERER_MAGIC(renderer, -1);
  1578 
  1579     /* If 'rect' == NULL, then outline the whole surface */
  1580     if (!rect) {
  1581         SDL_RenderGetViewport(renderer, &full_rect);
  1582         full_rect.x = 0;
  1583         full_rect.y = 0;
  1584         rect = &full_rect;
  1585     }
  1586     return SDL_RenderFillRects(renderer, rect, 1);
  1587 }
  1588 
  1589 int
  1590 SDL_RenderFillRects(SDL_Renderer * renderer,
  1591                     const SDL_Rect * rects, int count)
  1592 {
  1593     SDL_FRect *frects;
  1594     int i;
  1595     int status;
  1596 
  1597     CHECK_RENDERER_MAGIC(renderer, -1);
  1598 
  1599     if (!rects) {
  1600         return SDL_SetError("SDL_RenderFillRects(): Passed NULL rects");
  1601     }
  1602     if (count < 1) {
  1603         return 0;
  1604     }
  1605     /* Don't draw while we're hidden */
  1606     if (renderer->hidden) {
  1607         return 0;
  1608     }
  1609 
  1610     frects = SDL_stack_alloc(SDL_FRect, count);
  1611     if (!frects) {
  1612         return SDL_OutOfMemory();
  1613     }
  1614     for (i = 0; i < count; ++i) {
  1615         frects[i].x = rects[i].x * renderer->scale.x;
  1616         frects[i].y = rects[i].y * renderer->scale.y;
  1617         frects[i].w = rects[i].w * renderer->scale.x;
  1618         frects[i].h = rects[i].h * renderer->scale.y;
  1619     }
  1620 
  1621     status = renderer->RenderFillRects(renderer, frects, count);
  1622 
  1623     SDL_stack_free(frects);
  1624 
  1625     return status;
  1626 }
  1627 
  1628 int
  1629 SDL_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
  1630                const SDL_Rect * srcrect, const SDL_Rect * dstrect)
  1631 {
  1632     SDL_Rect real_srcrect = { 0, 0, 0, 0 };
  1633     SDL_Rect real_dstrect = { 0, 0, 0, 0 };
  1634     SDL_FRect frect;
  1635 
  1636     CHECK_RENDERER_MAGIC(renderer, -1);
  1637     CHECK_TEXTURE_MAGIC(texture, -1);
  1638 
  1639     if (renderer != texture->renderer) {
  1640         return SDL_SetError("Texture was not created with this renderer");
  1641     }
  1642 
  1643     real_srcrect.x = 0;
  1644     real_srcrect.y = 0;
  1645     real_srcrect.w = texture->w;
  1646     real_srcrect.h = texture->h;
  1647     if (srcrect) {
  1648         if (!SDL_IntersectRect(srcrect, &real_srcrect, &real_srcrect)) {
  1649             return 0;
  1650         }
  1651     }
  1652 
  1653     SDL_RenderGetViewport(renderer, &real_dstrect);
  1654     real_dstrect.x = 0;
  1655     real_dstrect.y = 0;
  1656     if (dstrect) {
  1657         if (!SDL_HasIntersection(dstrect, &real_dstrect)) {
  1658             return 0;
  1659         }
  1660         real_dstrect = *dstrect;
  1661     }
  1662 
  1663     if (texture->native) {
  1664         texture = texture->native;
  1665     }
  1666 
  1667     /* Don't draw while we're hidden */
  1668     if (renderer->hidden) {
  1669         return 0;
  1670     }
  1671 
  1672     frect.x = real_dstrect.x * renderer->scale.x;
  1673     frect.y = real_dstrect.y * renderer->scale.y;
  1674     frect.w = real_dstrect.w * renderer->scale.x;
  1675     frect.h = real_dstrect.h * renderer->scale.y;
  1676 
  1677     return renderer->RenderCopy(renderer, texture, &real_srcrect, &frect);
  1678 }
  1679 
  1680 
  1681 int
  1682 SDL_RenderCopyEx(SDL_Renderer * renderer, SDL_Texture * texture,
  1683                const SDL_Rect * srcrect, const SDL_Rect * dstrect,
  1684                const double angle, const SDL_Point *center, const SDL_RendererFlip flip)
  1685 {
  1686     SDL_Rect real_srcrect = { 0, 0, 0, 0 };
  1687     SDL_Rect real_dstrect = { 0, 0, 0, 0 };
  1688     SDL_Point real_center;
  1689     SDL_FRect frect;
  1690     SDL_FPoint fcenter;
  1691 
  1692     CHECK_RENDERER_MAGIC(renderer, -1);
  1693     CHECK_TEXTURE_MAGIC(texture, -1);
  1694 
  1695     if (renderer != texture->renderer) {
  1696         return SDL_SetError("Texture was not created with this renderer");
  1697     }
  1698     if (!renderer->RenderCopyEx) {
  1699         return SDL_SetError("Renderer does not support RenderCopyEx");
  1700     }
  1701 
  1702     real_srcrect.x = 0;
  1703     real_srcrect.y = 0;
  1704     real_srcrect.w = texture->w;
  1705     real_srcrect.h = texture->h;
  1706     if (srcrect) {
  1707         if (!SDL_IntersectRect(srcrect, &real_srcrect, &real_srcrect)) {
  1708             return 0;
  1709         }
  1710     }
  1711 
  1712     /* We don't intersect the dstrect with the viewport as RenderCopy does because of potential rotation clipping issues... TODO: should we? */
  1713     if (dstrect) {
  1714         real_dstrect = *dstrect;
  1715     } else {
  1716         SDL_RenderGetViewport(renderer, &real_dstrect);
  1717         real_dstrect.x = 0;
  1718         real_dstrect.y = 0;
  1719     }
  1720 
  1721     if (texture->native) {
  1722         texture = texture->native;
  1723     }
  1724 
  1725     if(center) real_center = *center;
  1726     else {
  1727         real_center.x = real_dstrect.w/2;
  1728         real_center.y = real_dstrect.h/2;
  1729     }
  1730 
  1731     frect.x = real_dstrect.x * renderer->scale.x;
  1732     frect.y = real_dstrect.y * renderer->scale.y;
  1733     frect.w = real_dstrect.w * renderer->scale.x;
  1734     frect.h = real_dstrect.h * renderer->scale.y;
  1735 
  1736     fcenter.x = real_center.x * renderer->scale.x;
  1737     fcenter.y = real_center.y * renderer->scale.y;
  1738 
  1739     return renderer->RenderCopyEx(renderer, texture, &real_srcrect, &frect, angle, &fcenter, flip);
  1740 }
  1741 
  1742 int
  1743 SDL_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
  1744                      Uint32 format, void * pixels, int pitch)
  1745 {
  1746     SDL_Rect real_rect;
  1747 
  1748     CHECK_RENDERER_MAGIC(renderer, -1);
  1749 
  1750     if (!renderer->RenderReadPixels) {
  1751         return SDL_Unsupported();
  1752     }
  1753 
  1754     if (!format) {
  1755         format = SDL_GetWindowPixelFormat(renderer->window);
  1756     }
  1757 
  1758     real_rect.x = renderer->viewport.x;
  1759     real_rect.y = renderer->viewport.y;
  1760     real_rect.w = renderer->viewport.w;
  1761     real_rect.h = renderer->viewport.h;
  1762     if (rect) {
  1763         if (!SDL_IntersectRect(rect, &real_rect, &real_rect)) {
  1764             return 0;
  1765         }
  1766         if (real_rect.y > rect->y) {
  1767             pixels = (Uint8 *)pixels + pitch * (real_rect.y - rect->y);
  1768         }
  1769         if (real_rect.x > rect->x) {
  1770             int bpp = SDL_BYTESPERPIXEL(format);
  1771             pixels = (Uint8 *)pixels + bpp * (real_rect.x - rect->x);
  1772         }
  1773     }
  1774 
  1775     return renderer->RenderReadPixels(renderer, &real_rect,
  1776                                       format, pixels, pitch);
  1777 }
  1778 
  1779 void
  1780 SDL_RenderPresent(SDL_Renderer * renderer)
  1781 {
  1782     CHECK_RENDERER_MAGIC(renderer, );
  1783 
  1784     /* Don't draw while we're hidden */
  1785     if (renderer->hidden) {
  1786         return;
  1787     }
  1788     renderer->RenderPresent(renderer);
  1789 }
  1790 
  1791 void
  1792 SDL_DestroyTexture(SDL_Texture * texture)
  1793 {
  1794     SDL_Renderer *renderer;
  1795 
  1796     CHECK_TEXTURE_MAGIC(texture, );
  1797 
  1798     renderer = texture->renderer;
  1799     if (texture == renderer->target) {
  1800         SDL_SetRenderTarget(renderer, NULL);
  1801     }
  1802 
  1803     texture->magic = NULL;
  1804 
  1805     if (texture->next) {
  1806         texture->next->prev = texture->prev;
  1807     }
  1808     if (texture->prev) {
  1809         texture->prev->next = texture->next;
  1810     } else {
  1811         renderer->textures = texture->next;
  1812     }
  1813 
  1814     if (texture->native) {
  1815         SDL_DestroyTexture(texture->native);
  1816     }
  1817     if (texture->yuv) {
  1818         SDL_SW_DestroyYUVTexture(texture->yuv);
  1819     }
  1820     SDL_free(texture->pixels);
  1821 
  1822     renderer->DestroyTexture(renderer, texture);
  1823     SDL_free(texture);
  1824 }
  1825 
  1826 void
  1827 SDL_DestroyRenderer(SDL_Renderer * renderer)
  1828 {
  1829     CHECK_RENDERER_MAGIC(renderer, );
  1830 
  1831     SDL_DelEventWatch(SDL_RendererEventWatch, renderer);
  1832 
  1833     /* Free existing textures for this renderer */
  1834     while (renderer->textures) {
  1835         SDL_DestroyTexture(renderer->textures);
  1836     }
  1837 
  1838     if (renderer->window) {
  1839         SDL_SetWindowData(renderer->window, SDL_WINDOWRENDERDATA, NULL);
  1840     }
  1841 
  1842     /* It's no longer magical... */
  1843     renderer->magic = NULL;
  1844 
  1845     /* Free the renderer instance */
  1846     renderer->DestroyRenderer(renderer);
  1847 }
  1848 
  1849 int SDL_GL_BindTexture(SDL_Texture *texture, float *texw, float *texh)
  1850 {
  1851     SDL_Renderer *renderer;
  1852 
  1853     CHECK_TEXTURE_MAGIC(texture, -1);
  1854     renderer = texture->renderer;
  1855     if (texture->native) {
  1856         return SDL_GL_BindTexture(texture->native, texw, texh);
  1857     } else if (renderer && renderer->GL_BindTexture) {
  1858         return renderer->GL_BindTexture(renderer, texture, texw, texh);
  1859     } else {
  1860         return SDL_Unsupported();
  1861     }
  1862 }
  1863 
  1864 int SDL_GL_UnbindTexture(SDL_Texture *texture)
  1865 {
  1866     SDL_Renderer *renderer;
  1867 
  1868     CHECK_TEXTURE_MAGIC(texture, -1);
  1869     renderer = texture->renderer;
  1870     if (renderer && renderer->GL_UnbindTexture) {
  1871         return renderer->GL_UnbindTexture(renderer, texture);
  1872     }
  1873 
  1874     return SDL_Unsupported();
  1875 }
  1876 
  1877 /* vi: set ts=4 sw=4 expandtab: */