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