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