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