src/render/SDL_render.c
author Sam Lantinga <slouken@libsdl.org>
Mon, 30 Sep 2013 22:16:14 -0700
changeset 7770 28031e0042b2
parent 7761 bddbfca922cd
child 7898 72af77fc6683
child 8535 e8ee0708ef5c
permissions -rw-r--r--
Fixed bug 2122 - SDL_CreateTexture allows illegal texture sizes

Lloyd Bryant

SDL_CreateTexture() is succeeding (i.e. returning a valid pointer) when the requested horizontal or vertical size of the texture exceeds the maximum allowed by the render. This results in hard-to-understand errors showing up when later attempting to use that texture (such as with SDL_SetRenderTarget()).
     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         SDL_SetError("Renderer doesn't support querying output size");
   352         return -1;
   353     }
   354 }
   355 
   356 static SDL_bool
   357 IsSupportedFormat(SDL_Renderer * renderer, Uint32 format)
   358 {
   359     Uint32 i;
   360 
   361     for (i = 0; i < renderer->info.num_texture_formats; ++i) {
   362         if (renderer->info.texture_formats[i] == format) {
   363             return SDL_TRUE;
   364         }
   365     }
   366     return SDL_FALSE;
   367 }
   368 
   369 static Uint32
   370 GetClosestSupportedFormat(SDL_Renderer * renderer, Uint32 format)
   371 {
   372     Uint32 i;
   373 
   374     if (SDL_ISPIXELFORMAT_FOURCC(format)) {
   375         /* Look for an exact match */
   376         for (i = 0; i < renderer->info.num_texture_formats; ++i) {
   377             if (renderer->info.texture_formats[i] == format) {
   378                 return renderer->info.texture_formats[i];
   379             }
   380         }
   381     } else {
   382         SDL_bool hasAlpha = SDL_ISPIXELFORMAT_ALPHA(format);
   383 
   384         /* We just want to match the first format that has the same channels */
   385         for (i = 0; i < renderer->info.num_texture_formats; ++i) {
   386             if (!SDL_ISPIXELFORMAT_FOURCC(renderer->info.texture_formats[i]) &&
   387                 SDL_ISPIXELFORMAT_ALPHA(renderer->info.texture_formats[i]) == hasAlpha) {
   388                 return renderer->info.texture_formats[i];
   389             }
   390         }
   391     }
   392     return renderer->info.texture_formats[0];
   393 }
   394 
   395 SDL_Texture *
   396 SDL_CreateTexture(SDL_Renderer * renderer, Uint32 format, int access, int w, int h)
   397 {
   398     SDL_Texture *texture;
   399 
   400     CHECK_RENDERER_MAGIC(renderer, NULL);
   401 
   402     if (!format) {
   403         format = renderer->info.texture_formats[0];
   404     }
   405     if (SDL_ISPIXELFORMAT_INDEXED(format)) {
   406         SDL_SetError("Palettized textures are not supported");
   407         return NULL;
   408     }
   409     if (w <= 0 || h <= 0) {
   410         SDL_SetError("Texture dimensions can't be 0");
   411         return NULL;
   412     }
   413     if ((renderer->info.max_texture_width && w > renderer->info.max_texture_width) ||
   414         (renderer->info.max_texture_height && h > renderer->info.max_texture_height)) {
   415         SDL_SetError("Texture dimensions are limited to %dx%d", renderer->info.max_texture_width, renderer->info.max_texture_height);
   416         return NULL;
   417     }
   418     texture = (SDL_Texture *) SDL_calloc(1, sizeof(*texture));
   419     if (!texture) {
   420         SDL_OutOfMemory();
   421         return NULL;
   422     }
   423     texture->magic = &texture_magic;
   424     texture->format = format;
   425     texture->access = access;
   426     texture->w = w;
   427     texture->h = h;
   428     texture->r = 255;
   429     texture->g = 255;
   430     texture->b = 255;
   431     texture->a = 255;
   432     texture->renderer = renderer;
   433     texture->next = renderer->textures;
   434     if (renderer->textures) {
   435         renderer->textures->prev = texture;
   436     }
   437     renderer->textures = texture;
   438 
   439     if (IsSupportedFormat(renderer, format)) {
   440         if (renderer->CreateTexture(renderer, texture) < 0) {
   441             SDL_DestroyTexture(texture);
   442             return 0;
   443         }
   444     } else {
   445         texture->native = SDL_CreateTexture(renderer,
   446                                 GetClosestSupportedFormat(renderer, format),
   447                                 access, w, h);
   448         if (!texture->native) {
   449             SDL_DestroyTexture(texture);
   450             return NULL;
   451         }
   452 
   453         /* Swap textures to have texture before texture->native in the list */
   454         texture->native->next = texture->next;
   455         if (texture->native->next) {
   456             texture->native->next->prev = texture->native;
   457         }
   458         texture->prev = texture->native->prev;
   459         if (texture->prev) {
   460             texture->prev->next = texture;
   461         }
   462         texture->native->prev = texture;
   463         texture->next = texture->native;
   464         renderer->textures = texture;
   465 
   466         if (SDL_ISPIXELFORMAT_FOURCC(texture->format)) {
   467             texture->yuv = SDL_SW_CreateYUVTexture(format, w, h);
   468             if (!texture->yuv) {
   469                 SDL_DestroyTexture(texture);
   470                 return NULL;
   471             }
   472         } else if (access == SDL_TEXTUREACCESS_STREAMING) {
   473             /* The pitch is 4 byte aligned */
   474             texture->pitch = (((w * SDL_BYTESPERPIXEL(format)) + 3) & ~3);
   475             texture->pixels = SDL_calloc(1, texture->pitch * h);
   476             if (!texture->pixels) {
   477                 SDL_DestroyTexture(texture);
   478                 return NULL;
   479             }
   480         }
   481     }
   482     return texture;
   483 }
   484 
   485 SDL_Texture *
   486 SDL_CreateTextureFromSurface(SDL_Renderer * renderer, SDL_Surface * surface)
   487 {
   488     const SDL_PixelFormat *fmt;
   489     SDL_bool needAlpha;
   490     Uint32 i;
   491     Uint32 format;
   492     SDL_Texture *texture;
   493 
   494     CHECK_RENDERER_MAGIC(renderer, NULL);
   495 
   496     if (!surface) {
   497         SDL_SetError("SDL_CreateTextureFromSurface() passed NULL surface");
   498         return NULL;
   499     }
   500 
   501     /* See what the best texture format is */
   502     fmt = surface->format;
   503     if (fmt->Amask || SDL_GetColorKey(surface, NULL) == 0) {
   504         needAlpha = SDL_TRUE;
   505     } else {
   506         needAlpha = SDL_FALSE;
   507     }
   508     format = renderer->info.texture_formats[0];
   509     for (i = 0; i < renderer->info.num_texture_formats; ++i) {
   510         if (!SDL_ISPIXELFORMAT_FOURCC(renderer->info.texture_formats[i]) &&
   511             SDL_ISPIXELFORMAT_ALPHA(renderer->info.texture_formats[i]) == needAlpha) {
   512             format = renderer->info.texture_formats[i];
   513             break;
   514         }
   515     }
   516 
   517     texture = SDL_CreateTexture(renderer, format, SDL_TEXTUREACCESS_STATIC,
   518                                 surface->w, surface->h);
   519     if (!texture) {
   520         return NULL;
   521     }
   522 
   523     if (format == surface->format->format) {
   524         if (SDL_MUSTLOCK(surface)) {
   525             SDL_LockSurface(surface);
   526             SDL_UpdateTexture(texture, NULL, surface->pixels, surface->pitch);
   527             SDL_UnlockSurface(surface);
   528         } else {
   529             SDL_UpdateTexture(texture, NULL, surface->pixels, surface->pitch);
   530         }
   531     } else {
   532         SDL_PixelFormat *dst_fmt;
   533         SDL_Surface *temp = NULL;
   534 
   535         /* Set up a destination surface for the texture update */
   536         dst_fmt = SDL_AllocFormat(format);
   537         temp = SDL_ConvertSurface(surface, dst_fmt, 0);
   538         SDL_FreeFormat(dst_fmt);
   539         if (temp) {
   540             SDL_UpdateTexture(texture, NULL, temp->pixels, temp->pitch);
   541             SDL_FreeSurface(temp);
   542         } else {
   543             SDL_DestroyTexture(texture);
   544             return NULL;
   545         }
   546     }
   547 
   548     {
   549         Uint8 r, g, b, a;
   550         SDL_BlendMode blendMode;
   551 
   552         SDL_GetSurfaceColorMod(surface, &r, &g, &b);
   553         SDL_SetTextureColorMod(texture, r, g, b);
   554 
   555         SDL_GetSurfaceAlphaMod(surface, &a);
   556         SDL_SetTextureAlphaMod(texture, a);
   557 
   558         if (SDL_GetColorKey(surface, NULL) == 0) {
   559             /* We converted to a texture with alpha format */
   560             SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_BLEND);
   561         } else {
   562             SDL_GetSurfaceBlendMode(surface, &blendMode);
   563             SDL_SetTextureBlendMode(texture, blendMode);
   564         }
   565     }
   566     return texture;
   567 }
   568 
   569 int
   570 SDL_QueryTexture(SDL_Texture * texture, Uint32 * format, int *access,
   571                  int *w, int *h)
   572 {
   573     CHECK_TEXTURE_MAGIC(texture, -1);
   574 
   575     if (format) {
   576         *format = texture->format;
   577     }
   578     if (access) {
   579         *access = texture->access;
   580     }
   581     if (w) {
   582         *w = texture->w;
   583     }
   584     if (h) {
   585         *h = texture->h;
   586     }
   587     return 0;
   588 }
   589 
   590 int
   591 SDL_SetTextureColorMod(SDL_Texture * texture, Uint8 r, Uint8 g, Uint8 b)
   592 {
   593     SDL_Renderer *renderer;
   594 
   595     CHECK_TEXTURE_MAGIC(texture, -1);
   596 
   597     renderer = texture->renderer;
   598     if (r < 255 || g < 255 || b < 255) {
   599         texture->modMode |= SDL_TEXTUREMODULATE_COLOR;
   600     } else {
   601         texture->modMode &= ~SDL_TEXTUREMODULATE_COLOR;
   602     }
   603     texture->r = r;
   604     texture->g = g;
   605     texture->b = b;
   606     if (texture->native) {
   607         return SDL_SetTextureColorMod(texture->native, r, g, b);
   608     } else if (renderer->SetTextureColorMod) {
   609         return renderer->SetTextureColorMod(renderer, texture);
   610     } else {
   611         return 0;
   612     }
   613 }
   614 
   615 int
   616 SDL_GetTextureColorMod(SDL_Texture * texture, Uint8 * r, Uint8 * g,
   617                        Uint8 * b)
   618 {
   619     CHECK_TEXTURE_MAGIC(texture, -1);
   620 
   621     if (r) {
   622         *r = texture->r;
   623     }
   624     if (g) {
   625         *g = texture->g;
   626     }
   627     if (b) {
   628         *b = texture->b;
   629     }
   630     return 0;
   631 }
   632 
   633 int
   634 SDL_SetTextureAlphaMod(SDL_Texture * texture, Uint8 alpha)
   635 {
   636     SDL_Renderer *renderer;
   637 
   638     CHECK_TEXTURE_MAGIC(texture, -1);
   639 
   640     renderer = texture->renderer;
   641     if (alpha < 255) {
   642         texture->modMode |= SDL_TEXTUREMODULATE_ALPHA;
   643     } else {
   644         texture->modMode &= ~SDL_TEXTUREMODULATE_ALPHA;
   645     }
   646     texture->a = alpha;
   647     if (texture->native) {
   648         return SDL_SetTextureAlphaMod(texture->native, alpha);
   649     } else if (renderer->SetTextureAlphaMod) {
   650         return renderer->SetTextureAlphaMod(renderer, texture);
   651     } else {
   652         return 0;
   653     }
   654 }
   655 
   656 int
   657 SDL_GetTextureAlphaMod(SDL_Texture * texture, Uint8 * alpha)
   658 {
   659     CHECK_TEXTURE_MAGIC(texture, -1);
   660 
   661     if (alpha) {
   662         *alpha = texture->a;
   663     }
   664     return 0;
   665 }
   666 
   667 int
   668 SDL_SetTextureBlendMode(SDL_Texture * texture, SDL_BlendMode blendMode)
   669 {
   670     SDL_Renderer *renderer;
   671 
   672     CHECK_TEXTURE_MAGIC(texture, -1);
   673 
   674     renderer = texture->renderer;
   675     texture->blendMode = blendMode;
   676     if (texture->native) {
   677         return SDL_SetTextureBlendMode(texture->native, blendMode);
   678     } else if (renderer->SetTextureBlendMode) {
   679         return renderer->SetTextureBlendMode(renderer, texture);
   680     } else {
   681         return 0;
   682     }
   683 }
   684 
   685 int
   686 SDL_GetTextureBlendMode(SDL_Texture * texture, SDL_BlendMode *blendMode)
   687 {
   688     CHECK_TEXTURE_MAGIC(texture, -1);
   689 
   690     if (blendMode) {
   691         *blendMode = texture->blendMode;
   692     }
   693     return 0;
   694 }
   695 
   696 static int
   697 SDL_UpdateTextureYUV(SDL_Texture * texture, const SDL_Rect * rect,
   698                      const void *pixels, int pitch)
   699 {
   700     SDL_Texture *native = texture->native;
   701     SDL_Rect full_rect;
   702 
   703     if (SDL_SW_UpdateYUVTexture(texture->yuv, rect, pixels, pitch) < 0) {
   704         return -1;
   705     }
   706 
   707     full_rect.x = 0;
   708     full_rect.y = 0;
   709     full_rect.w = texture->w;
   710     full_rect.h = texture->h;
   711     rect = &full_rect;
   712 
   713     if (texture->access == SDL_TEXTUREACCESS_STREAMING) {
   714         /* We can lock the texture and copy to it */
   715         void *native_pixels;
   716         int native_pitch;
   717 
   718         if (SDL_LockTexture(native, rect, &native_pixels, &native_pitch) < 0) {
   719             return -1;
   720         }
   721         SDL_SW_CopyYUVToRGB(texture->yuv, rect, native->format,
   722                             rect->w, rect->h, native_pixels, native_pitch);
   723         SDL_UnlockTexture(native);
   724     } else {
   725         /* Use a temporary buffer for updating */
   726         void *temp_pixels;
   727         int temp_pitch;
   728 
   729         temp_pitch = (((rect->w * SDL_BYTESPERPIXEL(native->format)) + 3) & ~3);
   730         temp_pixels = SDL_malloc(rect->h * temp_pitch);
   731         if (!temp_pixels) {
   732             return SDL_OutOfMemory();
   733         }
   734         SDL_SW_CopyYUVToRGB(texture->yuv, rect, native->format,
   735                             rect->w, rect->h, temp_pixels, temp_pitch);
   736         SDL_UpdateTexture(native, rect, temp_pixels, temp_pitch);
   737         SDL_free(temp_pixels);
   738     }
   739     return 0;
   740 }
   741 
   742 static int
   743 SDL_UpdateTextureNative(SDL_Texture * texture, const SDL_Rect * rect,
   744                         const void *pixels, int pitch)
   745 {
   746     SDL_Texture *native = texture->native;
   747 
   748     if (texture->access == SDL_TEXTUREACCESS_STREAMING) {
   749         /* We can lock the texture and copy to it */
   750         void *native_pixels;
   751         int native_pitch;
   752 
   753         if (SDL_LockTexture(native, rect, &native_pixels, &native_pitch) < 0) {
   754             return -1;
   755         }
   756         SDL_ConvertPixels(rect->w, rect->h,
   757                           texture->format, pixels, pitch,
   758                           native->format, native_pixels, native_pitch);
   759         SDL_UnlockTexture(native);
   760     } else {
   761         /* Use a temporary buffer for updating */
   762         void *temp_pixels;
   763         int temp_pitch;
   764 
   765         temp_pitch = (((rect->w * SDL_BYTESPERPIXEL(native->format)) + 3) & ~3);
   766         temp_pixels = SDL_malloc(rect->h * temp_pitch);
   767         if (!temp_pixels) {
   768             return SDL_OutOfMemory();
   769         }
   770         SDL_ConvertPixels(rect->w, rect->h,
   771                           texture->format, pixels, pitch,
   772                           native->format, temp_pixels, temp_pitch);
   773         SDL_UpdateTexture(native, rect, temp_pixels, temp_pitch);
   774         SDL_free(temp_pixels);
   775     }
   776     return 0;
   777 }
   778 
   779 int
   780 SDL_UpdateTexture(SDL_Texture * texture, const SDL_Rect * rect,
   781                   const void *pixels, int pitch)
   782 {
   783     SDL_Renderer *renderer;
   784     SDL_Rect full_rect;
   785 
   786     CHECK_TEXTURE_MAGIC(texture, -1);
   787 
   788     if (!pixels) {
   789         return SDL_InvalidParamError("pixels");
   790     }
   791     if (!pitch) {
   792         return SDL_InvalidParamError("pitch");
   793     }
   794 
   795     if (!rect) {
   796         full_rect.x = 0;
   797         full_rect.y = 0;
   798         full_rect.w = texture->w;
   799         full_rect.h = texture->h;
   800         rect = &full_rect;
   801     }
   802 
   803     if (texture->yuv) {
   804         return SDL_UpdateTextureYUV(texture, rect, pixels, pitch);
   805     } else if (texture->native) {
   806         return SDL_UpdateTextureNative(texture, rect, pixels, pitch);
   807     } else {
   808         renderer = texture->renderer;
   809         return renderer->UpdateTexture(renderer, texture, rect, pixels, pitch);
   810     }
   811 }
   812 
   813 static int
   814 SDL_UpdateTextureYUVPlanar(SDL_Texture * texture, const SDL_Rect * rect,
   815                            const Uint8 *Yplane, int Ypitch,
   816                            const Uint8 *Uplane, int Upitch,
   817                            const Uint8 *Vplane, int Vpitch)
   818 {
   819     SDL_Texture *native = texture->native;
   820     SDL_Rect full_rect;
   821 
   822     if (SDL_SW_UpdateYUVTexturePlanar(texture->yuv, rect, Yplane, Ypitch, Uplane, Upitch, Vplane, Vpitch) < 0) {
   823         return -1;
   824     }
   825 
   826     full_rect.x = 0;
   827     full_rect.y = 0;
   828     full_rect.w = texture->w;
   829     full_rect.h = texture->h;
   830     rect = &full_rect;
   831 
   832     if (texture->access == SDL_TEXTUREACCESS_STREAMING) {
   833         /* We can lock the texture and copy to it */
   834         void *native_pixels;
   835         int native_pitch;
   836 
   837         if (SDL_LockTexture(native, rect, &native_pixels, &native_pitch) < 0) {
   838             return -1;
   839         }
   840         SDL_SW_CopyYUVToRGB(texture->yuv, rect, native->format,
   841                             rect->w, rect->h, native_pixels, native_pitch);
   842         SDL_UnlockTexture(native);
   843     } else {
   844         /* Use a temporary buffer for updating */
   845         void *temp_pixels;
   846         int temp_pitch;
   847 
   848         temp_pitch = (((rect->w * SDL_BYTESPERPIXEL(native->format)) + 3) & ~3);
   849         temp_pixels = SDL_malloc(rect->h * temp_pitch);
   850         if (!temp_pixels) {
   851             return SDL_OutOfMemory();
   852         }
   853         SDL_SW_CopyYUVToRGB(texture->yuv, rect, native->format,
   854                             rect->w, rect->h, temp_pixels, temp_pitch);
   855         SDL_UpdateTexture(native, rect, temp_pixels, temp_pitch);
   856         SDL_free(temp_pixels);
   857     }
   858     return 0;
   859 }
   860 
   861 int SDL_UpdateYUVTexture(SDL_Texture * texture, const SDL_Rect * rect,
   862                          const Uint8 *Yplane, int Ypitch,
   863                          const Uint8 *Uplane, int Upitch,
   864                          const Uint8 *Vplane, int Vpitch)
   865 {
   866     SDL_Renderer *renderer;
   867     SDL_Rect full_rect;
   868 
   869     CHECK_TEXTURE_MAGIC(texture, -1);
   870 
   871     if (!Yplane) {
   872         return SDL_InvalidParamError("Yplane");
   873     }
   874     if (!Ypitch) {
   875         return SDL_InvalidParamError("Ypitch");
   876     }
   877     if (!Uplane) {
   878         return SDL_InvalidParamError("Uplane");
   879     }
   880     if (!Upitch) {
   881         return SDL_InvalidParamError("Upitch");
   882     }
   883     if (!Vplane) {
   884         return SDL_InvalidParamError("Vplane");
   885     }
   886     if (!Vpitch) {
   887         return SDL_InvalidParamError("Vpitch");
   888     }
   889 
   890     if (texture->format != SDL_PIXELFORMAT_YV12 &&
   891         texture->format != SDL_PIXELFORMAT_IYUV) {
   892         return SDL_SetError("Texture format must by YV12 or IYUV");
   893     }
   894 
   895     if (!rect) {
   896         full_rect.x = 0;
   897         full_rect.y = 0;
   898         full_rect.w = texture->w;
   899         full_rect.h = texture->h;
   900         rect = &full_rect;
   901     }
   902 
   903     if (texture->yuv) {
   904         return SDL_UpdateTextureYUVPlanar(texture, rect, Yplane, Ypitch, Uplane, Upitch, Vplane, Vpitch);
   905     } else {
   906         SDL_assert(!texture->native);
   907         renderer = texture->renderer;
   908         SDL_assert(renderer->UpdateTextureYUV);
   909 		if (renderer->UpdateTextureYUV) {
   910 			return renderer->UpdateTextureYUV(renderer, texture, rect, Yplane, Ypitch, Uplane, Upitch, Vplane, Vpitch);
   911 		} else {
   912 			return SDL_Unsupported();
   913 		}
   914 	}
   915 }
   916 
   917 static int
   918 SDL_LockTextureYUV(SDL_Texture * texture, const SDL_Rect * rect,
   919                    void **pixels, int *pitch)
   920 {
   921     return SDL_SW_LockYUVTexture(texture->yuv, rect, pixels, pitch);
   922 }
   923 
   924 static int
   925 SDL_LockTextureNative(SDL_Texture * texture, const SDL_Rect * rect,
   926                       void **pixels, int *pitch)
   927 {
   928     texture->locked_rect = *rect;
   929     *pixels = (void *) ((Uint8 *) texture->pixels +
   930                         rect->y * texture->pitch +
   931                         rect->x * SDL_BYTESPERPIXEL(texture->format));
   932     *pitch = texture->pitch;
   933     return 0;
   934 }
   935 
   936 int
   937 SDL_LockTexture(SDL_Texture * texture, const SDL_Rect * rect,
   938                 void **pixels, int *pitch)
   939 {
   940     SDL_Renderer *renderer;
   941     SDL_Rect full_rect;
   942 
   943     CHECK_TEXTURE_MAGIC(texture, -1);
   944 
   945     if (texture->access != SDL_TEXTUREACCESS_STREAMING) {
   946         return SDL_SetError("SDL_LockTexture(): texture must be streaming");
   947     }
   948 
   949     if (!rect) {
   950         full_rect.x = 0;
   951         full_rect.y = 0;
   952         full_rect.w = texture->w;
   953         full_rect.h = texture->h;
   954         rect = &full_rect;
   955     }
   956 
   957     if (texture->yuv) {
   958         return SDL_LockTextureYUV(texture, rect, pixels, pitch);
   959     } else if (texture->native) {
   960         return SDL_LockTextureNative(texture, rect, pixels, pitch);
   961     } else {
   962         renderer = texture->renderer;
   963         return renderer->LockTexture(renderer, texture, rect, pixels, pitch);
   964     }
   965 }
   966 
   967 static void
   968 SDL_UnlockTextureYUV(SDL_Texture * texture)
   969 {
   970     SDL_Texture *native = texture->native;
   971     void *native_pixels;
   972     int native_pitch;
   973     SDL_Rect rect;
   974 
   975     rect.x = 0;
   976     rect.y = 0;
   977     rect.w = texture->w;
   978     rect.h = texture->h;
   979 
   980     if (SDL_LockTexture(native, &rect, &native_pixels, &native_pitch) < 0) {
   981         return;
   982     }
   983     SDL_SW_CopyYUVToRGB(texture->yuv, &rect, native->format,
   984                         rect.w, rect.h, native_pixels, native_pitch);
   985     SDL_UnlockTexture(native);
   986 }
   987 
   988 static void
   989 SDL_UnlockTextureNative(SDL_Texture * texture)
   990 {
   991     SDL_Texture *native = texture->native;
   992     void *native_pixels;
   993     int native_pitch;
   994     const SDL_Rect *rect = &texture->locked_rect;
   995     const void* pixels = (void *) ((Uint8 *) texture->pixels +
   996                         rect->y * texture->pitch +
   997                         rect->x * SDL_BYTESPERPIXEL(texture->format));
   998     int pitch = texture->pitch;
   999 
  1000     if (SDL_LockTexture(native, rect, &native_pixels, &native_pitch) < 0) {
  1001         return;
  1002     }
  1003     SDL_ConvertPixels(rect->w, rect->h,
  1004                       texture->format, pixels, pitch,
  1005                       native->format, native_pixels, native_pitch);
  1006     SDL_UnlockTexture(native);
  1007 }
  1008 
  1009 void
  1010 SDL_UnlockTexture(SDL_Texture * texture)
  1011 {
  1012     SDL_Renderer *renderer;
  1013 
  1014     CHECK_TEXTURE_MAGIC(texture, );
  1015 
  1016     if (texture->access != SDL_TEXTUREACCESS_STREAMING) {
  1017         return;
  1018     }
  1019     if (texture->yuv) {
  1020         SDL_UnlockTextureYUV(texture);
  1021     } else if (texture->native) {
  1022         SDL_UnlockTextureNative(texture);
  1023     } else {
  1024         renderer = texture->renderer;
  1025         renderer->UnlockTexture(renderer, texture);
  1026     }
  1027 }
  1028 
  1029 SDL_bool
  1030 SDL_RenderTargetSupported(SDL_Renderer *renderer)
  1031 {
  1032     if (!renderer || !renderer->SetRenderTarget) {
  1033         return SDL_FALSE;
  1034     }
  1035     return (renderer->info.flags & SDL_RENDERER_TARGETTEXTURE) != 0;
  1036 }
  1037 
  1038 int
  1039 SDL_SetRenderTarget(SDL_Renderer *renderer, SDL_Texture *texture)
  1040 {
  1041     if (!SDL_RenderTargetSupported(renderer)) {
  1042         return SDL_Unsupported();
  1043     }
  1044     if (texture == renderer->target) {
  1045         /* Nothing to do! */
  1046         return 0;
  1047     }
  1048 
  1049     /* texture == NULL is valid and means reset the target to the window */
  1050     if (texture) {
  1051         CHECK_TEXTURE_MAGIC(texture, -1);
  1052         if (renderer != texture->renderer) {
  1053             return SDL_SetError("Texture was not created with this renderer");
  1054         }
  1055         if (texture->access != SDL_TEXTUREACCESS_TARGET) {
  1056             return SDL_SetError("Texture not created with SDL_TEXTUREACCESS_TARGET");
  1057         }
  1058         if (texture->native) {
  1059             /* Always render to the native texture */
  1060             texture = texture->native;
  1061         }
  1062     }
  1063 
  1064     if (texture && !renderer->target) {
  1065         /* Make a backup of the viewport */
  1066         renderer->viewport_backup = renderer->viewport;
  1067         renderer->clip_rect_backup = renderer->clip_rect;
  1068         renderer->scale_backup = renderer->scale;
  1069         renderer->logical_w_backup = renderer->logical_w;
  1070         renderer->logical_h_backup = renderer->logical_h;
  1071     }
  1072     renderer->target = texture;
  1073 
  1074     if (renderer->SetRenderTarget(renderer, texture) < 0) {
  1075         return -1;
  1076     }
  1077 
  1078     if (texture) {
  1079         renderer->viewport.x = 0;
  1080         renderer->viewport.y = 0;
  1081         renderer->viewport.w = texture->w;
  1082         renderer->viewport.h = texture->h;
  1083         renderer->scale.x = 1.0f;
  1084         renderer->scale.y = 1.0f;
  1085         renderer->logical_w = texture->w;
  1086         renderer->logical_h = texture->h;
  1087     } else {
  1088         renderer->viewport = renderer->viewport_backup;
  1089         renderer->clip_rect = renderer->clip_rect_backup;
  1090         renderer->scale = renderer->scale_backup;
  1091         renderer->logical_w = renderer->logical_w_backup;
  1092         renderer->logical_h = renderer->logical_h_backup;
  1093     }
  1094     if (renderer->UpdateViewport(renderer) < 0) {
  1095         return -1;
  1096     }
  1097     if (renderer->UpdateClipRect(renderer) < 0) {
  1098         return -1;
  1099     }
  1100 
  1101     /* All set! */
  1102     return 0;
  1103 }
  1104 
  1105 SDL_Texture *
  1106 SDL_GetRenderTarget(SDL_Renderer *renderer)
  1107 {
  1108     return renderer->target;
  1109 }
  1110 
  1111 static int
  1112 UpdateLogicalSize(SDL_Renderer *renderer)
  1113 {
  1114     int w, h;
  1115     float want_aspect;
  1116     float real_aspect;
  1117     float scale;
  1118     SDL_Rect viewport;
  1119 
  1120     if (SDL_GetRendererOutputSize(renderer, &w, &h) < 0) {
  1121         return -1;
  1122     }
  1123 
  1124     want_aspect = (float)renderer->logical_w / renderer->logical_h;
  1125     real_aspect = (float)w / h;
  1126 
  1127     /* Clear the scale because we're setting viewport in output coordinates */
  1128     SDL_RenderSetScale(renderer, 1.0f, 1.0f);
  1129 
  1130     if (SDL_fabs(want_aspect-real_aspect) < 0.0001) {
  1131         /* The aspect ratios are the same, just scale appropriately */
  1132         scale = (float)w / renderer->logical_w;
  1133         SDL_RenderSetViewport(renderer, NULL);
  1134     } else if (want_aspect > real_aspect) {
  1135         /* We want a wider aspect ratio than is available - letterbox it */
  1136         scale = (float)w / renderer->logical_w;
  1137         viewport.x = 0;
  1138         viewport.w = w;
  1139         viewport.h = (int)SDL_ceil(renderer->logical_h * scale);
  1140         viewport.y = (h - viewport.h) / 2;
  1141         SDL_RenderSetViewport(renderer, &viewport);
  1142     } else {
  1143         /* We want a narrower aspect ratio than is available - use side-bars */
  1144         scale = (float)h / renderer->logical_h;
  1145         viewport.y = 0;
  1146         viewport.h = h;
  1147         viewport.w = (int)SDL_ceil(renderer->logical_w * scale);
  1148         viewport.x = (w - viewport.w) / 2;
  1149         SDL_RenderSetViewport(renderer, &viewport);
  1150     }
  1151 
  1152     /* Set the new scale */
  1153     SDL_RenderSetScale(renderer, scale, scale);
  1154 
  1155     return 0;
  1156 }
  1157 
  1158 int
  1159 SDL_RenderSetLogicalSize(SDL_Renderer * renderer, int w, int h)
  1160 {
  1161     CHECK_RENDERER_MAGIC(renderer, -1);
  1162 
  1163     if (!w || !h) {
  1164         /* Clear any previous logical resolution */
  1165         renderer->logical_w = 0;
  1166         renderer->logical_h = 0;
  1167         SDL_RenderSetViewport(renderer, NULL);
  1168         SDL_RenderSetScale(renderer, 1.0f, 1.0f);
  1169         return 0;
  1170     }
  1171 
  1172     renderer->logical_w = w;
  1173     renderer->logical_h = h;
  1174 
  1175     return UpdateLogicalSize(renderer);
  1176 }
  1177 
  1178 void
  1179 SDL_RenderGetLogicalSize(SDL_Renderer * renderer, int *w, int *h)
  1180 {
  1181     CHECK_RENDERER_MAGIC(renderer, );
  1182 
  1183     if (w) {
  1184         *w = renderer->logical_w;
  1185     }
  1186     if (h) {
  1187         *h = renderer->logical_h;
  1188     }
  1189 }
  1190 
  1191 int
  1192 SDL_RenderSetViewport(SDL_Renderer * renderer, const SDL_Rect * rect)
  1193 {
  1194     CHECK_RENDERER_MAGIC(renderer, -1);
  1195 
  1196     if (rect) {
  1197         renderer->viewport.x = (int)SDL_floor(rect->x * renderer->scale.x);
  1198         renderer->viewport.y = (int)SDL_floor(rect->y * renderer->scale.y);
  1199         renderer->viewport.w = (int)SDL_ceil(rect->w * renderer->scale.x);
  1200         renderer->viewport.h = (int)SDL_ceil(rect->h * renderer->scale.y);
  1201     } else {
  1202         renderer->viewport.x = 0;
  1203         renderer->viewport.y = 0;
  1204         if (SDL_GetRendererOutputSize(renderer, &renderer->viewport.w, &renderer->viewport.h) < 0) {
  1205             return -1;
  1206         }
  1207     }
  1208     return renderer->UpdateViewport(renderer);
  1209 }
  1210 
  1211 void
  1212 SDL_RenderGetViewport(SDL_Renderer * renderer, SDL_Rect * rect)
  1213 {
  1214     CHECK_RENDERER_MAGIC(renderer, );
  1215 
  1216     if (rect) {
  1217         rect->x = (int)(renderer->viewport.x / renderer->scale.x);
  1218         rect->y = (int)(renderer->viewport.y / renderer->scale.y);
  1219         rect->w = (int)(renderer->viewport.w / renderer->scale.x);
  1220         rect->h = (int)(renderer->viewport.h / renderer->scale.y);
  1221     }
  1222 }
  1223 
  1224 int
  1225 SDL_RenderSetClipRect(SDL_Renderer * renderer, const SDL_Rect * rect)
  1226 {
  1227     CHECK_RENDERER_MAGIC(renderer, -1)
  1228 
  1229     if (rect) {
  1230         renderer->clip_rect.x = (int)SDL_floor(rect->x * renderer->scale.x);
  1231         renderer->clip_rect.y = (int)SDL_floor(rect->y * renderer->scale.y);
  1232         renderer->clip_rect.w = (int)SDL_ceil(rect->w * renderer->scale.x);
  1233         renderer->clip_rect.h = (int)SDL_ceil(rect->h * renderer->scale.y);
  1234     } else {
  1235         SDL_zero(renderer->clip_rect);
  1236     }
  1237     return renderer->UpdateClipRect(renderer);
  1238 }
  1239 
  1240 void
  1241 SDL_RenderGetClipRect(SDL_Renderer * renderer, SDL_Rect * rect)
  1242 {
  1243     CHECK_RENDERER_MAGIC(renderer, )
  1244 
  1245     if (rect) {
  1246         rect->x = (int)(renderer->clip_rect.x / renderer->scale.x);
  1247         rect->y = (int)(renderer->clip_rect.y / renderer->scale.y);
  1248         rect->w = (int)(renderer->clip_rect.w / renderer->scale.x);
  1249         rect->h = (int)(renderer->clip_rect.h / renderer->scale.y);
  1250     }
  1251 }
  1252 
  1253 int
  1254 SDL_RenderSetScale(SDL_Renderer * renderer, float scaleX, float scaleY)
  1255 {
  1256     CHECK_RENDERER_MAGIC(renderer, -1);
  1257 
  1258     renderer->scale.x = scaleX;
  1259     renderer->scale.y = scaleY;
  1260     return 0;
  1261 }
  1262 
  1263 void
  1264 SDL_RenderGetScale(SDL_Renderer * renderer, float *scaleX, float *scaleY)
  1265 {
  1266     CHECK_RENDERER_MAGIC(renderer, );
  1267 
  1268     if (scaleX) {
  1269         *scaleX = renderer->scale.x;
  1270     }
  1271     if (scaleY) {
  1272         *scaleY = renderer->scale.y;
  1273     }
  1274 }
  1275 
  1276 int
  1277 SDL_SetRenderDrawColor(SDL_Renderer * renderer,
  1278                        Uint8 r, Uint8 g, Uint8 b, Uint8 a)
  1279 {
  1280     CHECK_RENDERER_MAGIC(renderer, -1);
  1281 
  1282     renderer->r = r;
  1283     renderer->g = g;
  1284     renderer->b = b;
  1285     renderer->a = a;
  1286     return 0;
  1287 }
  1288 
  1289 int
  1290 SDL_GetRenderDrawColor(SDL_Renderer * renderer,
  1291                        Uint8 * r, Uint8 * g, Uint8 * b, Uint8 * a)
  1292 {
  1293     CHECK_RENDERER_MAGIC(renderer, -1);
  1294 
  1295     if (r) {
  1296         *r = renderer->r;
  1297     }
  1298     if (g) {
  1299         *g = renderer->g;
  1300     }
  1301     if (b) {
  1302         *b = renderer->b;
  1303     }
  1304     if (a) {
  1305         *a = renderer->a;
  1306     }
  1307     return 0;
  1308 }
  1309 
  1310 int
  1311 SDL_SetRenderDrawBlendMode(SDL_Renderer * renderer, SDL_BlendMode blendMode)
  1312 {
  1313     CHECK_RENDERER_MAGIC(renderer, -1);
  1314 
  1315     renderer->blendMode = blendMode;
  1316     return 0;
  1317 }
  1318 
  1319 int
  1320 SDL_GetRenderDrawBlendMode(SDL_Renderer * renderer, SDL_BlendMode *blendMode)
  1321 {
  1322     CHECK_RENDERER_MAGIC(renderer, -1);
  1323 
  1324     *blendMode = renderer->blendMode;
  1325     return 0;
  1326 }
  1327 
  1328 int
  1329 SDL_RenderClear(SDL_Renderer * renderer)
  1330 {
  1331     CHECK_RENDERER_MAGIC(renderer, -1);
  1332 
  1333     /* Don't draw while we're hidden */
  1334     if (renderer->hidden) {
  1335         return 0;
  1336     }
  1337     return renderer->RenderClear(renderer);
  1338 }
  1339 
  1340 int
  1341 SDL_RenderDrawPoint(SDL_Renderer * renderer, int x, int y)
  1342 {
  1343     SDL_Point point;
  1344 
  1345     point.x = x;
  1346     point.y = y;
  1347     return SDL_RenderDrawPoints(renderer, &point, 1);
  1348 }
  1349 
  1350 static int
  1351 RenderDrawPointsWithRects(SDL_Renderer * renderer,
  1352                      const SDL_Point * points, int count)
  1353 {
  1354     SDL_FRect *frects;
  1355     int i;
  1356     int status;
  1357 
  1358     frects = SDL_stack_alloc(SDL_FRect, count);
  1359     if (!frects) {
  1360         return SDL_OutOfMemory();
  1361     }
  1362     for (i = 0; i < count; ++i) {
  1363         frects[i].x = points[i].x * renderer->scale.x;
  1364         frects[i].y = points[i].y * renderer->scale.y;
  1365         frects[i].w = renderer->scale.x;
  1366         frects[i].h = renderer->scale.y;
  1367     }
  1368 
  1369     status = renderer->RenderFillRects(renderer, frects, count);
  1370 
  1371     SDL_stack_free(frects);
  1372 
  1373     return status;
  1374 }
  1375 
  1376 int
  1377 SDL_RenderDrawPoints(SDL_Renderer * renderer,
  1378                      const SDL_Point * points, int count)
  1379 {
  1380     SDL_FPoint *fpoints;
  1381     int i;
  1382     int status;
  1383 
  1384     CHECK_RENDERER_MAGIC(renderer, -1);
  1385 
  1386     if (!points) {
  1387         return SDL_SetError("SDL_RenderDrawPoints(): Passed NULL points");
  1388     }
  1389     if (count < 1) {
  1390         return 0;
  1391     }
  1392     /* Don't draw while we're hidden */
  1393     if (renderer->hidden) {
  1394         return 0;
  1395     }
  1396 
  1397     if (renderer->scale.x != 1.0f || renderer->scale.y != 1.0f) {
  1398         return RenderDrawPointsWithRects(renderer, points, count);
  1399     }
  1400 
  1401     fpoints = SDL_stack_alloc(SDL_FPoint, count);
  1402     if (!fpoints) {
  1403         return SDL_OutOfMemory();
  1404     }
  1405     for (i = 0; i < count; ++i) {
  1406         fpoints[i].x = points[i].x * renderer->scale.x;
  1407         fpoints[i].y = points[i].y * renderer->scale.y;
  1408     }
  1409 
  1410     status = renderer->RenderDrawPoints(renderer, fpoints, count);
  1411 
  1412     SDL_stack_free(fpoints);
  1413 
  1414     return status;
  1415 }
  1416 
  1417 int
  1418 SDL_RenderDrawLine(SDL_Renderer * renderer, int x1, int y1, int x2, int y2)
  1419 {
  1420     SDL_Point points[2];
  1421 
  1422     points[0].x = x1;
  1423     points[0].y = y1;
  1424     points[1].x = x2;
  1425     points[1].y = y2;
  1426     return SDL_RenderDrawLines(renderer, points, 2);
  1427 }
  1428 
  1429 static int
  1430 RenderDrawLinesWithRects(SDL_Renderer * renderer,
  1431                      const SDL_Point * points, int count)
  1432 {
  1433     SDL_FRect *frect;
  1434     SDL_FRect *frects;
  1435     SDL_FPoint fpoints[2];
  1436     int i, nrects;
  1437     int status;
  1438 
  1439     frects = SDL_stack_alloc(SDL_FRect, count-1);
  1440     if (!frects) {
  1441         return SDL_OutOfMemory();
  1442     }
  1443 
  1444     status = 0;
  1445     nrects = 0;
  1446     for (i = 0; i < count-1; ++i) {
  1447         if (points[i].x == points[i+1].x) {
  1448             int minY = SDL_min(points[i].y, points[i+1].y);
  1449             int maxY = SDL_max(points[i].y, points[i+1].y);
  1450 
  1451             frect = &frects[nrects++];
  1452             frect->x = points[i].x * renderer->scale.x;
  1453             frect->y = minY * renderer->scale.y;
  1454             frect->w = renderer->scale.x;
  1455             frect->h = (maxY - minY + 1) * renderer->scale.y;
  1456         } else if (points[i].y == points[i+1].y) {
  1457             int minX = SDL_min(points[i].x, points[i+1].x);
  1458             int maxX = SDL_max(points[i].x, points[i+1].x);
  1459 
  1460             frect = &frects[nrects++];
  1461             frect->x = minX * renderer->scale.x;
  1462             frect->y = points[i].y * renderer->scale.y;
  1463             frect->w = (maxX - minX + 1) * renderer->scale.x;
  1464             frect->h = renderer->scale.y;
  1465         } else {
  1466             /* FIXME: We can't use a rect for this line... */
  1467             fpoints[0].x = points[i].x * renderer->scale.x;
  1468             fpoints[0].y = points[i].y * renderer->scale.y;
  1469             fpoints[1].x = points[i+1].x * renderer->scale.x;
  1470             fpoints[1].y = points[i+1].y * renderer->scale.y;
  1471             status += renderer->RenderDrawLines(renderer, fpoints, 2);
  1472         }
  1473     }
  1474 
  1475     status += renderer->RenderFillRects(renderer, frects, nrects);
  1476 
  1477     SDL_stack_free(frects);
  1478 
  1479     if (status < 0) {
  1480         status = -1;
  1481     }
  1482     return status;
  1483 }
  1484 
  1485 int
  1486 SDL_RenderDrawLines(SDL_Renderer * renderer,
  1487                     const SDL_Point * points, int count)
  1488 {
  1489     SDL_FPoint *fpoints;
  1490     int i;
  1491     int status;
  1492 
  1493     CHECK_RENDERER_MAGIC(renderer, -1);
  1494 
  1495     if (!points) {
  1496         return SDL_SetError("SDL_RenderDrawLines(): Passed NULL points");
  1497     }
  1498     if (count < 2) {
  1499         return 0;
  1500     }
  1501     /* Don't draw while we're hidden */
  1502     if (renderer->hidden) {
  1503         return 0;
  1504     }
  1505 
  1506     if (renderer->scale.x != 1.0f || renderer->scale.y != 1.0f) {
  1507         return RenderDrawLinesWithRects(renderer, points, count);
  1508     }
  1509 
  1510     fpoints = SDL_stack_alloc(SDL_FPoint, count);
  1511     if (!fpoints) {
  1512         return SDL_OutOfMemory();
  1513     }
  1514     for (i = 0; i < count; ++i) {
  1515         fpoints[i].x = points[i].x * renderer->scale.x;
  1516         fpoints[i].y = points[i].y * renderer->scale.y;
  1517     }
  1518 
  1519     status = renderer->RenderDrawLines(renderer, fpoints, count);
  1520 
  1521     SDL_stack_free(fpoints);
  1522 
  1523     return status;
  1524 }
  1525 
  1526 int
  1527 SDL_RenderDrawRect(SDL_Renderer * renderer, const SDL_Rect * rect)
  1528 {
  1529     SDL_Rect full_rect;
  1530     SDL_Point points[5];
  1531 
  1532     CHECK_RENDERER_MAGIC(renderer, -1);
  1533 
  1534     /* If 'rect' == NULL, then outline the whole surface */
  1535     if (!rect) {
  1536         SDL_RenderGetViewport(renderer, &full_rect);
  1537         full_rect.x = 0;
  1538         full_rect.y = 0;
  1539         rect = &full_rect;
  1540     }
  1541 
  1542     points[0].x = rect->x;
  1543     points[0].y = rect->y;
  1544     points[1].x = rect->x+rect->w-1;
  1545     points[1].y = rect->y;
  1546     points[2].x = rect->x+rect->w-1;
  1547     points[2].y = rect->y+rect->h-1;
  1548     points[3].x = rect->x;
  1549     points[3].y = rect->y+rect->h-1;
  1550     points[4].x = rect->x;
  1551     points[4].y = rect->y;
  1552     return SDL_RenderDrawLines(renderer, points, 5);
  1553 }
  1554 
  1555 int
  1556 SDL_RenderDrawRects(SDL_Renderer * renderer,
  1557                     const SDL_Rect * rects, int count)
  1558 {
  1559     int i;
  1560 
  1561     CHECK_RENDERER_MAGIC(renderer, -1);
  1562 
  1563     if (!rects) {
  1564         return SDL_SetError("SDL_RenderDrawRects(): Passed NULL rects");
  1565     }
  1566     if (count < 1) {
  1567         return 0;
  1568     }
  1569 
  1570     /* Don't draw while we're hidden */
  1571     if (renderer->hidden) {
  1572         return 0;
  1573     }
  1574     for (i = 0; i < count; ++i) {
  1575         if (SDL_RenderDrawRect(renderer, &rects[i]) < 0) {
  1576             return -1;
  1577         }
  1578     }
  1579     return 0;
  1580 }
  1581 
  1582 int
  1583 SDL_RenderFillRect(SDL_Renderer * renderer, const SDL_Rect * rect)
  1584 {
  1585     SDL_Rect full_rect = { 0, 0, 0, 0 };
  1586 
  1587     CHECK_RENDERER_MAGIC(renderer, -1);
  1588 
  1589     /* If 'rect' == NULL, then outline the whole surface */
  1590     if (!rect) {
  1591         SDL_RenderGetViewport(renderer, &full_rect);
  1592         full_rect.x = 0;
  1593         full_rect.y = 0;
  1594         rect = &full_rect;
  1595     }
  1596     return SDL_RenderFillRects(renderer, rect, 1);
  1597 }
  1598 
  1599 int
  1600 SDL_RenderFillRects(SDL_Renderer * renderer,
  1601                     const SDL_Rect * rects, int count)
  1602 {
  1603     SDL_FRect *frects;
  1604     int i;
  1605     int status;
  1606 
  1607     CHECK_RENDERER_MAGIC(renderer, -1);
  1608 
  1609     if (!rects) {
  1610         return SDL_SetError("SDL_RenderFillRects(): Passed NULL rects");
  1611     }
  1612     if (count < 1) {
  1613         return 0;
  1614     }
  1615     /* Don't draw while we're hidden */
  1616     if (renderer->hidden) {
  1617         return 0;
  1618     }
  1619 
  1620     frects = SDL_stack_alloc(SDL_FRect, count);
  1621     if (!frects) {
  1622         return SDL_OutOfMemory();
  1623     }
  1624     for (i = 0; i < count; ++i) {
  1625         frects[i].x = rects[i].x * renderer->scale.x;
  1626         frects[i].y = rects[i].y * renderer->scale.y;
  1627         frects[i].w = rects[i].w * renderer->scale.x;
  1628         frects[i].h = rects[i].h * renderer->scale.y;
  1629     }
  1630 
  1631     status = renderer->RenderFillRects(renderer, frects, count);
  1632 
  1633     SDL_stack_free(frects);
  1634 
  1635     return status;
  1636 }
  1637 
  1638 int
  1639 SDL_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
  1640                const SDL_Rect * srcrect, const SDL_Rect * dstrect)
  1641 {
  1642     SDL_Rect real_srcrect = { 0, 0, 0, 0 };
  1643     SDL_Rect real_dstrect = { 0, 0, 0, 0 };
  1644     SDL_FRect frect;
  1645 
  1646     CHECK_RENDERER_MAGIC(renderer, -1);
  1647     CHECK_TEXTURE_MAGIC(texture, -1);
  1648 
  1649     if (renderer != texture->renderer) {
  1650         return SDL_SetError("Texture was not created with this renderer");
  1651     }
  1652 
  1653     real_srcrect.x = 0;
  1654     real_srcrect.y = 0;
  1655     real_srcrect.w = texture->w;
  1656     real_srcrect.h = texture->h;
  1657     if (srcrect) {
  1658         if (!SDL_IntersectRect(srcrect, &real_srcrect, &real_srcrect)) {
  1659             return 0;
  1660         }
  1661     }
  1662 
  1663     SDL_RenderGetViewport(renderer, &real_dstrect);
  1664     real_dstrect.x = 0;
  1665     real_dstrect.y = 0;
  1666     if (dstrect) {
  1667         if (!SDL_HasIntersection(dstrect, &real_dstrect)) {
  1668             return 0;
  1669         }
  1670         real_dstrect = *dstrect;
  1671     }
  1672 
  1673     if (texture->native) {
  1674         texture = texture->native;
  1675     }
  1676 
  1677     /* Don't draw while we're hidden */
  1678     if (renderer->hidden) {
  1679         return 0;
  1680     }
  1681 
  1682     frect.x = real_dstrect.x * renderer->scale.x;
  1683     frect.y = real_dstrect.y * renderer->scale.y;
  1684     frect.w = real_dstrect.w * renderer->scale.x;
  1685     frect.h = real_dstrect.h * renderer->scale.y;
  1686 
  1687     return renderer->RenderCopy(renderer, texture, &real_srcrect, &frect);
  1688 }
  1689 
  1690 
  1691 int
  1692 SDL_RenderCopyEx(SDL_Renderer * renderer, SDL_Texture * texture,
  1693                const SDL_Rect * srcrect, const SDL_Rect * dstrect,
  1694                const double angle, const SDL_Point *center, const SDL_RendererFlip flip)
  1695 {
  1696     SDL_Rect real_srcrect = { 0, 0, 0, 0 };
  1697     SDL_Rect real_dstrect = { 0, 0, 0, 0 };
  1698     SDL_Point real_center;
  1699     SDL_FRect frect;
  1700     SDL_FPoint fcenter;
  1701 
  1702     CHECK_RENDERER_MAGIC(renderer, -1);
  1703     CHECK_TEXTURE_MAGIC(texture, -1);
  1704 
  1705     if (renderer != texture->renderer) {
  1706         return SDL_SetError("Texture was not created with this renderer");
  1707     }
  1708     if (!renderer->RenderCopyEx) {
  1709         return SDL_SetError("Renderer does not support RenderCopyEx");
  1710     }
  1711 
  1712     real_srcrect.x = 0;
  1713     real_srcrect.y = 0;
  1714     real_srcrect.w = texture->w;
  1715     real_srcrect.h = texture->h;
  1716     if (srcrect) {
  1717         if (!SDL_IntersectRect(srcrect, &real_srcrect, &real_srcrect)) {
  1718             return 0;
  1719         }
  1720     }
  1721 
  1722     /* We don't intersect the dstrect with the viewport as RenderCopy does because of potential rotation clipping issues... TODO: should we? */
  1723     if (dstrect) {
  1724         real_dstrect = *dstrect;
  1725     } else {
  1726         SDL_RenderGetViewport(renderer, &real_dstrect);
  1727         real_dstrect.x = 0;
  1728         real_dstrect.y = 0;
  1729     }
  1730 
  1731     if (texture->native) {
  1732         texture = texture->native;
  1733     }
  1734 
  1735     if(center) real_center = *center;
  1736     else {
  1737         real_center.x = real_dstrect.w/2;
  1738         real_center.y = real_dstrect.h/2;
  1739     }
  1740 
  1741     frect.x = real_dstrect.x * renderer->scale.x;
  1742     frect.y = real_dstrect.y * renderer->scale.y;
  1743     frect.w = real_dstrect.w * renderer->scale.x;
  1744     frect.h = real_dstrect.h * renderer->scale.y;
  1745 
  1746     fcenter.x = real_center.x * renderer->scale.x;
  1747     fcenter.y = real_center.y * renderer->scale.y;
  1748 
  1749     return renderer->RenderCopyEx(renderer, texture, &real_srcrect, &frect, angle, &fcenter, flip);
  1750 }
  1751 
  1752 int
  1753 SDL_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
  1754                      Uint32 format, void * pixels, int pitch)
  1755 {
  1756     SDL_Rect real_rect;
  1757 
  1758     CHECK_RENDERER_MAGIC(renderer, -1);
  1759 
  1760     if (!renderer->RenderReadPixels) {
  1761         return SDL_Unsupported();
  1762     }
  1763 
  1764     if (!format) {
  1765         format = SDL_GetWindowPixelFormat(renderer->window);
  1766     }
  1767 
  1768     real_rect.x = renderer->viewport.x;
  1769     real_rect.y = renderer->viewport.y;
  1770     real_rect.w = renderer->viewport.w;
  1771     real_rect.h = renderer->viewport.h;
  1772     if (rect) {
  1773         if (!SDL_IntersectRect(rect, &real_rect, &real_rect)) {
  1774             return 0;
  1775         }
  1776         if (real_rect.y > rect->y) {
  1777             pixels = (Uint8 *)pixels + pitch * (real_rect.y - rect->y);
  1778         }
  1779         if (real_rect.x > rect->x) {
  1780             int bpp = SDL_BYTESPERPIXEL(format);
  1781             pixels = (Uint8 *)pixels + bpp * (real_rect.x - rect->x);
  1782         }
  1783     }
  1784 
  1785     return renderer->RenderReadPixels(renderer, &real_rect,
  1786                                       format, pixels, pitch);
  1787 }
  1788 
  1789 void
  1790 SDL_RenderPresent(SDL_Renderer * renderer)
  1791 {
  1792     CHECK_RENDERER_MAGIC(renderer, );
  1793 
  1794     /* Don't draw while we're hidden */
  1795     if (renderer->hidden) {
  1796         return;
  1797     }
  1798     renderer->RenderPresent(renderer);
  1799 }
  1800 
  1801 void
  1802 SDL_DestroyTexture(SDL_Texture * texture)
  1803 {
  1804     SDL_Renderer *renderer;
  1805 
  1806     CHECK_TEXTURE_MAGIC(texture, );
  1807 
  1808     renderer = texture->renderer;
  1809     if (texture == renderer->target) {
  1810         SDL_SetRenderTarget(renderer, NULL);
  1811     }
  1812 
  1813     texture->magic = NULL;
  1814 
  1815     if (texture->next) {
  1816         texture->next->prev = texture->prev;
  1817     }
  1818     if (texture->prev) {
  1819         texture->prev->next = texture->next;
  1820     } else {
  1821         renderer->textures = texture->next;
  1822     }
  1823 
  1824     if (texture->native) {
  1825         SDL_DestroyTexture(texture->native);
  1826     }
  1827     if (texture->yuv) {
  1828         SDL_SW_DestroyYUVTexture(texture->yuv);
  1829     }
  1830     SDL_free(texture->pixels);
  1831 
  1832     renderer->DestroyTexture(renderer, texture);
  1833     SDL_free(texture);
  1834 }
  1835 
  1836 void
  1837 SDL_DestroyRenderer(SDL_Renderer * renderer)
  1838 {
  1839     CHECK_RENDERER_MAGIC(renderer, );
  1840 
  1841     SDL_DelEventWatch(SDL_RendererEventWatch, renderer);
  1842 
  1843     /* Free existing textures for this renderer */
  1844     while (renderer->textures) {
  1845         SDL_DestroyTexture(renderer->textures);
  1846     }
  1847 
  1848     if (renderer->window) {
  1849         SDL_SetWindowData(renderer->window, SDL_WINDOWRENDERDATA, NULL);
  1850     }
  1851 
  1852     /* It's no longer magical... */
  1853     renderer->magic = NULL;
  1854 
  1855     /* Free the renderer instance */
  1856     renderer->DestroyRenderer(renderer);
  1857 }
  1858 
  1859 int SDL_GL_BindTexture(SDL_Texture *texture, float *texw, float *texh)
  1860 {
  1861     SDL_Renderer *renderer;
  1862 
  1863     CHECK_TEXTURE_MAGIC(texture, -1);
  1864     renderer = texture->renderer;
  1865     if (texture->native) {
  1866         return SDL_GL_BindTexture(texture->native, texw, texh);
  1867     } else if (renderer && renderer->GL_BindTexture) {
  1868         return renderer->GL_BindTexture(renderer, texture, texw, texh);
  1869     } else {
  1870         return SDL_Unsupported();
  1871     }
  1872 }
  1873 
  1874 int SDL_GL_UnbindTexture(SDL_Texture *texture)
  1875 {
  1876     SDL_Renderer *renderer;
  1877 
  1878     CHECK_TEXTURE_MAGIC(texture, -1);
  1879     renderer = texture->renderer;
  1880     if (renderer && renderer->GL_UnbindTexture) {
  1881         return renderer->GL_UnbindTexture(renderer, texture);
  1882     }
  1883 
  1884     return SDL_Unsupported();
  1885 }
  1886 
  1887 /* vi: set ts=4 sw=4 expandtab: */