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