src/render/SDL_render.c
author Sam Lantinga <slouken@libsdl.org>
Wed, 29 May 2013 03:07:55 -0700
changeset 7239 04dda95ba22c
parent 7191 75360622e65f
child 7240 39eb4958950a
permissions -rw-r--r--
Fixed bug 1622 - SDL_RenderSetViewport with empty SDL_Rect raises wrong error for OpenGL rendering backend

It's now legal to set an empty viewport rect - it will prevent any rendering.

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