src/render/SDL_render.c
author Sam Lantinga <slouken@libsdl.org>
Wed, 05 Jun 2013 22:33:10 -0700
changeset 7286 04087a99e3f4
parent 7240 39eb4958950a
child 7318 46a5a6b8678e
permissions -rw-r--r--
Added testautomation to the Visual Studio 2008 project.
     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_SIZE_CHANGED) {
   114                 if (renderer->logical_w) {
   115                     UpdateLogicalSize(renderer);
   116                 } else {
   117                     /* Window was resized, reset viewport */
   118                     int w, h;
   119 
   120                     SDL_GetWindowSize(window, &w, &h);
   121                     if (renderer->target) {
   122                         renderer->viewport_backup.x = 0;
   123                         renderer->viewport_backup.y = 0;
   124                         renderer->viewport_backup.w = w;
   125                         renderer->viewport_backup.h = h;
   126                     } else {
   127                         renderer->viewport.x = 0;
   128                         renderer->viewport.y = 0;
   129                         renderer->viewport.w = w;
   130                         renderer->viewport.h = h;
   131                         renderer->UpdateViewport(renderer);
   132                     }
   133                 }
   134             } else if (event->window.event == SDL_WINDOWEVENT_HIDDEN) {
   135                 renderer->hidden = SDL_TRUE;
   136             } else if (event->window.event == SDL_WINDOWEVENT_SHOWN) {
   137                 if (!(SDL_GetWindowFlags(window) & SDL_WINDOW_MINIMIZED)) {
   138                     renderer->hidden = SDL_FALSE;
   139                 }
   140             } else if (event->window.event == SDL_WINDOWEVENT_MINIMIZED) {
   141                 renderer->hidden = SDL_TRUE;
   142             } else if (event->window.event == SDL_WINDOWEVENT_RESTORED) {
   143                 if (!(SDL_GetWindowFlags(window) & SDL_WINDOW_HIDDEN)) {
   144                     renderer->hidden = SDL_FALSE;
   145                 }
   146             }
   147         }
   148     } else if (event->type == SDL_MOUSEMOTION) {
   149         if (renderer->logical_w) {
   150             event->motion.x -= renderer->viewport.x;
   151             event->motion.y -= renderer->viewport.y;
   152             event->motion.x = (int)(event->motion.x / renderer->scale.x);
   153             event->motion.y = (int)(event->motion.y / renderer->scale.y);
   154         }
   155     } else if (event->type == SDL_MOUSEBUTTONDOWN ||
   156                event->type == SDL_MOUSEBUTTONUP) {
   157         if (renderer->logical_w) {
   158             event->button.x -= renderer->viewport.x;
   159             event->button.y -= renderer->viewport.y;
   160             event->button.x = (int)(event->button.x / renderer->scale.x);
   161             event->button.y = (int)(event->button.y / renderer->scale.y);
   162         }
   163     }
   164     return 0;
   165 }
   166 
   167 int
   168 SDL_CreateWindowAndRenderer(int width, int height, Uint32 window_flags,
   169                             SDL_Window **window, SDL_Renderer **renderer)
   170 {
   171     *window = SDL_CreateWindow(NULL, SDL_WINDOWPOS_UNDEFINED,
   172                                      SDL_WINDOWPOS_UNDEFINED,
   173                                      width, height, window_flags);
   174     if (!*window) {
   175         *renderer = NULL;
   176         return -1;
   177     }
   178 
   179     *renderer = SDL_CreateRenderer(*window, -1, 0);
   180     if (!*renderer) {
   181         return -1;
   182     }
   183 
   184     return 0;
   185 }
   186 
   187 SDL_Renderer *
   188 SDL_CreateRenderer(SDL_Window * window, int index, Uint32 flags)
   189 {
   190 #if !SDL_RENDER_DISABLED
   191     SDL_Renderer *renderer = NULL;
   192     int n = SDL_GetNumRenderDrivers();
   193     const char *hint;
   194 
   195     if (!window) {
   196         SDL_SetError("Invalid window");
   197         return NULL;
   198     }
   199 
   200     if (SDL_GetRenderer(window)) {
   201         SDL_SetError("Renderer already associated with window");
   202         return NULL;
   203     }
   204 
   205     hint = SDL_GetHint(SDL_HINT_RENDER_VSYNC);
   206     if (hint) {
   207         if (*hint == '0') {
   208             flags &= ~SDL_RENDERER_PRESENTVSYNC;
   209         } else {
   210             flags |= SDL_RENDERER_PRESENTVSYNC;
   211         }
   212     }
   213 
   214     if (index < 0) {
   215         hint = SDL_GetHint(SDL_HINT_RENDER_DRIVER);
   216         if (hint) {
   217             for (index = 0; index < n; ++index) {
   218                 const SDL_RenderDriver *driver = render_drivers[index];
   219 
   220                 if (SDL_strcasecmp(hint, driver->info.name) == 0) {
   221                     /* Create a new renderer instance */
   222                     renderer = driver->CreateRenderer(window, flags);
   223                     break;
   224                 }
   225             }
   226         }
   227 
   228         if (!renderer) {
   229             for (index = 0; index < n; ++index) {
   230                 const SDL_RenderDriver *driver = render_drivers[index];
   231 
   232                 if ((driver->info.flags & flags) == flags) {
   233                     /* Create a new renderer instance */
   234                     renderer = driver->CreateRenderer(window, flags);
   235                     if (renderer) {
   236                         /* Yay, we got one! */
   237                         break;
   238                     }
   239                 }
   240             }
   241         }
   242         if (index == n) {
   243             SDL_SetError("Couldn't find matching render driver");
   244             return NULL;
   245         }
   246     } else {
   247         if (index >= SDL_GetNumRenderDrivers()) {
   248             SDL_SetError("index must be -1 or in the range of 0 - %d",
   249                          SDL_GetNumRenderDrivers() - 1);
   250             return NULL;
   251         }
   252         /* Create a new renderer instance */
   253         renderer = render_drivers[index]->CreateRenderer(window, flags);
   254     }
   255 
   256     if (renderer) {
   257         renderer->magic = &renderer_magic;
   258         renderer->window = window;
   259         renderer->scale.x = 1.0f;
   260         renderer->scale.y = 1.0f;
   261 
   262         if (SDL_GetWindowFlags(window) & (SDL_WINDOW_HIDDEN|SDL_WINDOW_MINIMIZED)) {
   263             renderer->hidden = SDL_TRUE;
   264         } else {
   265             renderer->hidden = SDL_FALSE;
   266         }
   267 
   268         SDL_SetWindowData(window, SDL_WINDOWRENDERDATA, renderer);
   269 
   270         SDL_RenderSetViewport(renderer, NULL);
   271 
   272         SDL_AddEventWatch(SDL_RendererEventWatch, renderer);
   273 
   274         SDL_LogInfo(SDL_LOG_CATEGORY_RENDER,
   275                     "Created renderer: %s", renderer->info.name);
   276     }
   277     return renderer;
   278 #else
   279     SDL_SetError("SDL not built with rendering support");
   280     return NULL;
   281 #endif
   282 }
   283 
   284 SDL_Renderer *
   285 SDL_CreateSoftwareRenderer(SDL_Surface * surface)
   286 {
   287 #if !SDL_RENDER_DISABLED
   288     SDL_Renderer *renderer;
   289 
   290     renderer = SW_CreateRendererForSurface(surface);
   291 
   292     if (renderer) {
   293         renderer->magic = &renderer_magic;
   294         renderer->scale.x = 1.0f;
   295         renderer->scale.y = 1.0f;
   296 
   297         SDL_RenderSetViewport(renderer, NULL);
   298     }
   299     return renderer;
   300 #else
   301     SDL_SetError("SDL not built with rendering support");
   302     return NULL;
   303 #endif /* !SDL_RENDER_DISABLED */
   304 }
   305 
   306 SDL_Renderer *
   307 SDL_GetRenderer(SDL_Window * window)
   308 {
   309     return (SDL_Renderer *)SDL_GetWindowData(window, SDL_WINDOWRENDERDATA);
   310 }
   311 
   312 int
   313 SDL_GetRendererInfo(SDL_Renderer * renderer, SDL_RendererInfo * info)
   314 {
   315     CHECK_RENDERER_MAGIC(renderer, -1);
   316 
   317     *info = renderer->info;
   318     return 0;
   319 }
   320 
   321 int
   322 SDL_GetRendererOutputSize(SDL_Renderer * renderer, int *w, int *h)
   323 {
   324     CHECK_RENDERER_MAGIC(renderer, -1);
   325 
   326     if (renderer->target) {
   327         return SDL_QueryTexture(renderer->target, NULL, NULL, w, h);
   328     } else if (renderer->window) {
   329         SDL_GetWindowSize(renderer->window, w, h);
   330         return 0;
   331     } else if (renderer->GetOutputSize) {
   332         return renderer->GetOutputSize(renderer, w, h);
   333     } else {
   334         /* This should never happen */
   335         SDL_SetError("Renderer doesn't support querying output size");
   336         return -1;
   337     }
   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 (SDL_GetRendererOutputSize(renderer, &w, &h) < 0) {
   989         return -1;
   990     }
   991 
   992     want_aspect = (float)renderer->logical_w / renderer->logical_h;
   993     real_aspect = (float)w / h;
   994 
   995     /* Clear the scale because we're setting viewport in output coordinates */
   996     SDL_RenderSetScale(renderer, 1.0f, 1.0f);
   997 
   998     if (SDL_fabs(want_aspect-real_aspect) < 0.0001) {
   999         /* The aspect ratios are the same, just scale appropriately */
  1000         scale = (float)w / renderer->logical_w;
  1001         SDL_RenderSetViewport(renderer, NULL);
  1002     } else if (want_aspect > real_aspect) {
  1003         /* We want a wider aspect ratio than is available - letterbox it */
  1004         scale = (float)w / renderer->logical_w;
  1005         viewport.x = 0;
  1006         viewport.w = w;
  1007         viewport.h = (int)SDL_ceil(renderer->logical_h * scale);
  1008         viewport.y = (h - viewport.h) / 2;
  1009         SDL_RenderSetViewport(renderer, &viewport);
  1010     } else {
  1011         /* We want a narrower aspect ratio than is available - use side-bars */
  1012         scale = (float)h / renderer->logical_h;
  1013         viewport.y = 0;
  1014         viewport.h = h;
  1015         viewport.w = (int)SDL_ceil(renderer->logical_w * scale);
  1016         viewport.x = (w - viewport.w) / 2;
  1017         SDL_RenderSetViewport(renderer, &viewport);
  1018     }
  1019 
  1020     /* Set the new scale */
  1021     SDL_RenderSetScale(renderer, scale, scale);
  1022 
  1023     return 0;
  1024 }
  1025 
  1026 int
  1027 SDL_RenderSetLogicalSize(SDL_Renderer * renderer, int w, int h)
  1028 {
  1029     CHECK_RENDERER_MAGIC(renderer, -1);
  1030 
  1031     if (!w || !h) {
  1032         /* Clear any previous logical resolution */
  1033         renderer->logical_w = 0;
  1034         renderer->logical_h = 0;
  1035         SDL_RenderSetViewport(renderer, NULL);
  1036         SDL_RenderSetScale(renderer, 1.0f, 1.0f);
  1037         return 0;
  1038     }
  1039 
  1040     renderer->logical_w = w;
  1041     renderer->logical_h = h;
  1042 
  1043     return UpdateLogicalSize(renderer);
  1044 }
  1045 
  1046 void
  1047 SDL_RenderGetLogicalSize(SDL_Renderer * renderer, int *w, int *h)
  1048 {
  1049     CHECK_RENDERER_MAGIC(renderer, );
  1050 
  1051     if (w) {
  1052         *w = renderer->logical_w;
  1053     }
  1054     if (h) {
  1055         *h = renderer->logical_h;
  1056     }
  1057 }
  1058 
  1059 int
  1060 SDL_RenderSetViewport(SDL_Renderer * renderer, const SDL_Rect * rect)
  1061 {
  1062     CHECK_RENDERER_MAGIC(renderer, -1);
  1063 
  1064     if (rect) {
  1065         renderer->viewport.x = (int)SDL_floor(rect->x * renderer->scale.x);
  1066         renderer->viewport.y = (int)SDL_floor(rect->y * renderer->scale.y);
  1067         renderer->viewport.w = (int)SDL_ceil(rect->w * renderer->scale.x);
  1068         renderer->viewport.h = (int)SDL_ceil(rect->h * renderer->scale.y);
  1069     } else {
  1070         renderer->viewport.x = 0;
  1071         renderer->viewport.y = 0;
  1072         if (SDL_GetRendererOutputSize(renderer, &renderer->viewport.w, &renderer->viewport.h) < 0) {
  1073             return -1;
  1074         }
  1075     }
  1076     return renderer->UpdateViewport(renderer);
  1077 }
  1078 
  1079 void
  1080 SDL_RenderGetViewport(SDL_Renderer * renderer, SDL_Rect * rect)
  1081 {
  1082     CHECK_RENDERER_MAGIC(renderer, );
  1083 
  1084     if (rect) {
  1085         rect->x = (int)(renderer->viewport.x / renderer->scale.x);
  1086         rect->y = (int)(renderer->viewport.y / renderer->scale.y);
  1087         rect->w = (int)(renderer->viewport.w / renderer->scale.x);
  1088         rect->h = (int)(renderer->viewport.h / renderer->scale.y);
  1089     }
  1090 }
  1091 
  1092 int
  1093 SDL_RenderSetClipRect(SDL_Renderer * renderer, const SDL_Rect * rect)
  1094 {
  1095     CHECK_RENDERER_MAGIC(renderer, -1)
  1096 
  1097     if (rect) {
  1098         renderer->clip_rect.x = (int)SDL_floor(rect->x * renderer->scale.x);
  1099         renderer->clip_rect.y = (int)SDL_floor(rect->y * renderer->scale.y);
  1100         renderer->clip_rect.w = (int)SDL_ceil(rect->w * renderer->scale.x);
  1101         renderer->clip_rect.h = (int)SDL_ceil(rect->h * renderer->scale.y);
  1102     } else {
  1103         SDL_zero(renderer->clip_rect);
  1104     }
  1105     return renderer->UpdateClipRect(renderer);
  1106 }
  1107 
  1108 void
  1109 SDL_RenderGetClipRect(SDL_Renderer * renderer, SDL_Rect * rect)
  1110 {
  1111     CHECK_RENDERER_MAGIC(renderer, )
  1112 
  1113     if (rect) {
  1114         rect->x = (int)(renderer->clip_rect.x / renderer->scale.x);
  1115         rect->y = (int)(renderer->clip_rect.y / renderer->scale.y);
  1116         rect->w = (int)(renderer->clip_rect.w / renderer->scale.x);
  1117         rect->h = (int)(renderer->clip_rect.h / renderer->scale.y);
  1118     }
  1119 }
  1120 
  1121 int
  1122 SDL_RenderSetScale(SDL_Renderer * renderer, float scaleX, float scaleY)
  1123 {
  1124     CHECK_RENDERER_MAGIC(renderer, -1);
  1125 
  1126     renderer->scale.x = scaleX;
  1127     renderer->scale.y = scaleY;
  1128     return 0;
  1129 }
  1130 
  1131 void
  1132 SDL_RenderGetScale(SDL_Renderer * renderer, float *scaleX, float *scaleY)
  1133 {
  1134     CHECK_RENDERER_MAGIC(renderer, );
  1135 
  1136     if (scaleX) {
  1137         *scaleX = renderer->scale.x;
  1138     }
  1139     if (scaleY) {
  1140         *scaleY = renderer->scale.y;
  1141     }
  1142 }
  1143 
  1144 int
  1145 SDL_SetRenderDrawColor(SDL_Renderer * renderer,
  1146                        Uint8 r, Uint8 g, Uint8 b, Uint8 a)
  1147 {
  1148     CHECK_RENDERER_MAGIC(renderer, -1);
  1149 
  1150     renderer->r = r;
  1151     renderer->g = g;
  1152     renderer->b = b;
  1153     renderer->a = a;
  1154     return 0;
  1155 }
  1156 
  1157 int
  1158 SDL_GetRenderDrawColor(SDL_Renderer * renderer,
  1159                        Uint8 * r, Uint8 * g, Uint8 * b, Uint8 * a)
  1160 {
  1161     CHECK_RENDERER_MAGIC(renderer, -1);
  1162 
  1163     if (r) {
  1164         *r = renderer->r;
  1165     }
  1166     if (g) {
  1167         *g = renderer->g;
  1168     }
  1169     if (b) {
  1170         *b = renderer->b;
  1171     }
  1172     if (a) {
  1173         *a = renderer->a;
  1174     }
  1175     return 0;
  1176 }
  1177 
  1178 int
  1179 SDL_SetRenderDrawBlendMode(SDL_Renderer * renderer, SDL_BlendMode blendMode)
  1180 {
  1181     CHECK_RENDERER_MAGIC(renderer, -1);
  1182 
  1183     renderer->blendMode = blendMode;
  1184     return 0;
  1185 }
  1186 
  1187 int
  1188 SDL_GetRenderDrawBlendMode(SDL_Renderer * renderer, SDL_BlendMode *blendMode)
  1189 {
  1190     CHECK_RENDERER_MAGIC(renderer, -1);
  1191 
  1192     *blendMode = renderer->blendMode;
  1193     return 0;
  1194 }
  1195 
  1196 int
  1197 SDL_RenderClear(SDL_Renderer * renderer)
  1198 {
  1199     CHECK_RENDERER_MAGIC(renderer, -1);
  1200 
  1201     /* Don't draw while we're hidden */
  1202     if (renderer->hidden) {
  1203         return 0;
  1204     }
  1205     return renderer->RenderClear(renderer);
  1206 }
  1207 
  1208 int
  1209 SDL_RenderDrawPoint(SDL_Renderer * renderer, int x, int y)
  1210 {
  1211     SDL_Point point;
  1212 
  1213     point.x = x;
  1214     point.y = y;
  1215     return SDL_RenderDrawPoints(renderer, &point, 1);
  1216 }
  1217 
  1218 static int
  1219 RenderDrawPointsWithRects(SDL_Renderer * renderer,
  1220                      const SDL_Point * points, int count)
  1221 {
  1222     SDL_FRect *frects;
  1223     int i;
  1224     int status;
  1225 
  1226     frects = SDL_stack_alloc(SDL_FRect, count);
  1227     if (!frects) {
  1228         return SDL_OutOfMemory();
  1229     }
  1230     for (i = 0; i < count; ++i) {
  1231         frects[i].x = points[i].x * renderer->scale.x;
  1232         frects[i].y = points[i].y * renderer->scale.y;
  1233         frects[i].w = renderer->scale.x;
  1234         frects[i].h = renderer->scale.y;
  1235     }
  1236 
  1237     status = renderer->RenderFillRects(renderer, frects, count);
  1238 
  1239     SDL_stack_free(frects);
  1240 
  1241     return status;
  1242 }
  1243 
  1244 int
  1245 SDL_RenderDrawPoints(SDL_Renderer * renderer,
  1246                      const SDL_Point * points, int count)
  1247 {
  1248     SDL_FPoint *fpoints;
  1249     int i;
  1250     int status;
  1251 
  1252     CHECK_RENDERER_MAGIC(renderer, -1);
  1253 
  1254     if (!points) {
  1255         return SDL_SetError("SDL_RenderDrawPoints(): Passed NULL points");
  1256     }
  1257     if (count < 1) {
  1258         return 0;
  1259     }
  1260     /* Don't draw while we're hidden */
  1261     if (renderer->hidden) {
  1262         return 0;
  1263     }
  1264 
  1265     if (renderer->scale.x != 1.0f || renderer->scale.y != 1.0f) {
  1266         return RenderDrawPointsWithRects(renderer, points, count);
  1267     }
  1268 
  1269     fpoints = SDL_stack_alloc(SDL_FPoint, count);
  1270     if (!fpoints) {
  1271         return SDL_OutOfMemory();
  1272     }
  1273     for (i = 0; i < count; ++i) {
  1274         fpoints[i].x = points[i].x * renderer->scale.x;
  1275         fpoints[i].y = points[i].y * renderer->scale.y;
  1276     }
  1277 
  1278     status = renderer->RenderDrawPoints(renderer, fpoints, count);
  1279 
  1280     SDL_stack_free(fpoints);
  1281 
  1282     return status;
  1283 }
  1284 
  1285 int
  1286 SDL_RenderDrawLine(SDL_Renderer * renderer, int x1, int y1, int x2, int y2)
  1287 {
  1288     SDL_Point points[2];
  1289 
  1290     points[0].x = x1;
  1291     points[0].y = y1;
  1292     points[1].x = x2;
  1293     points[1].y = y2;
  1294     return SDL_RenderDrawLines(renderer, points, 2);
  1295 }
  1296 
  1297 static int
  1298 RenderDrawLinesWithRects(SDL_Renderer * renderer,
  1299                      const SDL_Point * points, int count)
  1300 {
  1301     SDL_FRect *frect;
  1302     SDL_FRect *frects;
  1303     SDL_FPoint fpoints[2];
  1304     int i, nrects;
  1305     int status;
  1306 
  1307     frects = SDL_stack_alloc(SDL_FRect, count-1);
  1308     if (!frects) {
  1309         return SDL_OutOfMemory();
  1310     }
  1311 
  1312     status = 0;
  1313     nrects = 0;
  1314     for (i = 0; i < count-1; ++i) {
  1315         if (points[i].x == points[i+1].x) {
  1316             int minY = SDL_min(points[i].y, points[i+1].y);
  1317             int maxY = SDL_max(points[i].y, points[i+1].y);
  1318 
  1319             frect = &frects[nrects++];
  1320             frect->x = points[i].x * renderer->scale.x;
  1321             frect->y = minY * renderer->scale.y;
  1322             frect->w = renderer->scale.x;
  1323             frect->h = (maxY - minY + 1) * renderer->scale.y;
  1324         } else if (points[i].y == points[i+1].y) {
  1325             int minX = SDL_min(points[i].x, points[i+1].x);
  1326             int maxX = SDL_max(points[i].x, points[i+1].x);
  1327 
  1328             frect = &frects[nrects++];
  1329             frect->x = minX * renderer->scale.x;
  1330             frect->y = points[i].y * renderer->scale.y;
  1331             frect->w = (maxX - minX + 1) * renderer->scale.x;
  1332             frect->h = renderer->scale.y;
  1333         } else {
  1334             /* FIXME: We can't use a rect for this line... */
  1335             fpoints[0].x = points[i].x * renderer->scale.x;
  1336             fpoints[0].y = points[i].y * renderer->scale.y;
  1337             fpoints[1].x = points[i+1].x * renderer->scale.x;
  1338             fpoints[1].y = points[i+1].y * renderer->scale.y;
  1339             status += renderer->RenderDrawLines(renderer, fpoints, 2);
  1340         }
  1341     }
  1342 
  1343     status += renderer->RenderFillRects(renderer, frects, nrects);
  1344 
  1345     SDL_stack_free(frects);
  1346 
  1347     if (status < 0) {
  1348         status = -1;
  1349     }
  1350     return status;
  1351 }
  1352 
  1353 int
  1354 SDL_RenderDrawLines(SDL_Renderer * renderer,
  1355                     const SDL_Point * points, int count)
  1356 {
  1357     SDL_FPoint *fpoints;
  1358     int i;
  1359     int status;
  1360 
  1361     CHECK_RENDERER_MAGIC(renderer, -1);
  1362 
  1363     if (!points) {
  1364         return SDL_SetError("SDL_RenderDrawLines(): Passed NULL points");
  1365     }
  1366     if (count < 2) {
  1367         return 0;
  1368     }
  1369     /* Don't draw while we're hidden */
  1370     if (renderer->hidden) {
  1371         return 0;
  1372     }
  1373 
  1374     if (renderer->scale.x != 1.0f || renderer->scale.y != 1.0f) {
  1375         return RenderDrawLinesWithRects(renderer, points, count);
  1376     }
  1377 
  1378     fpoints = SDL_stack_alloc(SDL_FPoint, count);
  1379     if (!fpoints) {
  1380         return SDL_OutOfMemory();
  1381     }
  1382     for (i = 0; i < count; ++i) {
  1383         fpoints[i].x = points[i].x * renderer->scale.x;
  1384         fpoints[i].y = points[i].y * renderer->scale.y;
  1385     }
  1386 
  1387     status = renderer->RenderDrawLines(renderer, fpoints, count);
  1388 
  1389     SDL_stack_free(fpoints);
  1390 
  1391     return status;
  1392 }
  1393 
  1394 int
  1395 SDL_RenderDrawRect(SDL_Renderer * renderer, const SDL_Rect * rect)
  1396 {
  1397     SDL_Rect full_rect;
  1398     SDL_Point points[5];
  1399 
  1400     CHECK_RENDERER_MAGIC(renderer, -1);
  1401 
  1402     /* If 'rect' == NULL, then outline the whole surface */
  1403     if (!rect) {
  1404         SDL_RenderGetViewport(renderer, &full_rect);
  1405         full_rect.x = 0;
  1406         full_rect.y = 0;
  1407         rect = &full_rect;
  1408     }
  1409 
  1410     points[0].x = rect->x;
  1411     points[0].y = rect->y;
  1412     points[1].x = rect->x+rect->w-1;
  1413     points[1].y = rect->y;
  1414     points[2].x = rect->x+rect->w-1;
  1415     points[2].y = rect->y+rect->h-1;
  1416     points[3].x = rect->x;
  1417     points[3].y = rect->y+rect->h-1;
  1418     points[4].x = rect->x;
  1419     points[4].y = rect->y;
  1420     return SDL_RenderDrawLines(renderer, points, 5);
  1421 }
  1422 
  1423 int
  1424 SDL_RenderDrawRects(SDL_Renderer * renderer,
  1425                     const SDL_Rect * rects, int count)
  1426 {
  1427     int i;
  1428 
  1429     CHECK_RENDERER_MAGIC(renderer, -1);
  1430 
  1431     if (!rects) {
  1432         return SDL_SetError("SDL_RenderDrawRects(): Passed NULL rects");
  1433     }
  1434     if (count < 1) {
  1435         return 0;
  1436     }
  1437 
  1438     /* Don't draw while we're hidden */
  1439     if (renderer->hidden) {
  1440         return 0;
  1441     }
  1442     for (i = 0; i < count; ++i) {
  1443         if (SDL_RenderDrawRect(renderer, &rects[i]) < 0) {
  1444             return -1;
  1445         }
  1446     }
  1447     return 0;
  1448 }
  1449 
  1450 int
  1451 SDL_RenderFillRect(SDL_Renderer * renderer, const SDL_Rect * rect)
  1452 {
  1453     SDL_Rect full_rect;
  1454 
  1455     CHECK_RENDERER_MAGIC(renderer, -1);
  1456 
  1457     /* If 'rect' == NULL, then outline the whole surface */
  1458     if (!rect) {
  1459         SDL_RenderGetViewport(renderer, &full_rect);
  1460         full_rect.x = 0;
  1461         full_rect.y = 0;
  1462         rect = &full_rect;
  1463     }
  1464     return SDL_RenderFillRects(renderer, rect, 1);
  1465 }
  1466 
  1467 int
  1468 SDL_RenderFillRects(SDL_Renderer * renderer,
  1469                     const SDL_Rect * rects, int count)
  1470 {
  1471     SDL_FRect *frects;
  1472     int i;
  1473     int status;
  1474 
  1475     CHECK_RENDERER_MAGIC(renderer, -1);
  1476 
  1477     if (!rects) {
  1478         return SDL_SetError("SDL_RenderFillRects(): Passed NULL rects");
  1479     }
  1480     if (count < 1) {
  1481         return 0;
  1482     }
  1483     /* Don't draw while we're hidden */
  1484     if (renderer->hidden) {
  1485         return 0;
  1486     }
  1487 
  1488     frects = SDL_stack_alloc(SDL_FRect, count);
  1489     if (!frects) {
  1490         return SDL_OutOfMemory();
  1491     }
  1492     for (i = 0; i < count; ++i) {
  1493         frects[i].x = rects[i].x * renderer->scale.x;
  1494         frects[i].y = rects[i].y * renderer->scale.y;
  1495         frects[i].w = rects[i].w * renderer->scale.x;
  1496         frects[i].h = rects[i].h * renderer->scale.y;
  1497     }
  1498 
  1499     status = renderer->RenderFillRects(renderer, frects, count);
  1500 
  1501     SDL_stack_free(frects);
  1502 
  1503     return status;
  1504 }
  1505 
  1506 int
  1507 SDL_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
  1508                const SDL_Rect * srcrect, const SDL_Rect * dstrect)
  1509 {
  1510     SDL_Rect real_srcrect = { 0, 0, 0, 0 };
  1511     SDL_Rect real_dstrect = { 0, 0, 0, 0 };
  1512     SDL_FRect frect;
  1513 
  1514     CHECK_RENDERER_MAGIC(renderer, -1);
  1515     CHECK_TEXTURE_MAGIC(texture, -1);
  1516 
  1517     if (renderer != texture->renderer) {
  1518         return SDL_SetError("Texture was not created with this renderer");
  1519     }
  1520 
  1521     real_srcrect.x = 0;
  1522     real_srcrect.y = 0;
  1523     real_srcrect.w = texture->w;
  1524     real_srcrect.h = texture->h;
  1525     if (srcrect) {
  1526         if (!SDL_IntersectRect(srcrect, &real_srcrect, &real_srcrect)) {
  1527             return 0;
  1528         }
  1529     }
  1530 
  1531     SDL_RenderGetViewport(renderer, &real_dstrect);
  1532     real_dstrect.x = 0;
  1533     real_dstrect.y = 0;
  1534     if (dstrect) {
  1535         if (!SDL_IntersectRect(dstrect, &real_dstrect, &real_dstrect)) {
  1536             return 0;
  1537         }
  1538         /* Clip srcrect by the same amount as dstrect was clipped */
  1539         if (dstrect->w != real_dstrect.w) {
  1540             int deltax = (real_dstrect.x - dstrect->x);
  1541             int deltaw = (real_dstrect.w - dstrect->w);
  1542             real_srcrect.x += (deltax * real_srcrect.w) / dstrect->w;
  1543             real_srcrect.w += (deltaw * real_srcrect.w) / dstrect->w;
  1544         }
  1545         if (dstrect->h != real_dstrect.h) {
  1546             int deltay = (real_dstrect.y - dstrect->y);
  1547             int deltah = (real_dstrect.h - dstrect->h);
  1548             real_srcrect.y += (deltay * real_srcrect.h) / dstrect->h;
  1549             real_srcrect.h += (deltah * real_srcrect.h) / dstrect->h;
  1550         }
  1551     }
  1552 
  1553     if (texture->native) {
  1554         texture = texture->native;
  1555     }
  1556 
  1557     /* Don't draw while we're hidden */
  1558     if (renderer->hidden) {
  1559         return 0;
  1560     }
  1561 
  1562     frect.x = real_dstrect.x * renderer->scale.x;
  1563     frect.y = real_dstrect.y * renderer->scale.y;
  1564     frect.w = real_dstrect.w * renderer->scale.x;
  1565     frect.h = real_dstrect.h * renderer->scale.y;
  1566 
  1567     return renderer->RenderCopy(renderer, texture, &real_srcrect, &frect);
  1568 }
  1569 
  1570 
  1571 int
  1572 SDL_RenderCopyEx(SDL_Renderer * renderer, SDL_Texture * texture,
  1573                const SDL_Rect * srcrect, const SDL_Rect * dstrect,
  1574                const double angle, const SDL_Point *center, const SDL_RendererFlip flip)
  1575 {
  1576     SDL_Rect real_srcrect = { 0, 0, 0, 0 };
  1577     SDL_Rect real_dstrect = { 0, 0, 0, 0 };
  1578     SDL_Point real_center;
  1579     SDL_FRect frect;
  1580     SDL_FPoint fcenter;
  1581 
  1582     CHECK_RENDERER_MAGIC(renderer, -1);
  1583     CHECK_TEXTURE_MAGIC(texture, -1);
  1584 
  1585     if (renderer != texture->renderer) {
  1586         return SDL_SetError("Texture was not created with this renderer");
  1587     }
  1588     if (!renderer->RenderCopyEx) {
  1589         return SDL_SetError("Renderer does not support RenderCopyEx");
  1590     }
  1591 
  1592     real_srcrect.x = 0;
  1593     real_srcrect.y = 0;
  1594     real_srcrect.w = texture->w;
  1595     real_srcrect.h = texture->h;
  1596     if (srcrect) {
  1597         if (!SDL_IntersectRect(srcrect, &real_srcrect, &real_srcrect)) {
  1598             return 0;
  1599         }
  1600     }
  1601 
  1602     /* We don't intersect the dstrect with the viewport as RenderCopy does because of potential rotation clipping issues... TODO: should we? */
  1603     if (dstrect) {
  1604         real_dstrect = *dstrect;
  1605     } else {
  1606         SDL_RenderGetViewport(renderer, &real_dstrect);
  1607         real_dstrect.x = 0;
  1608         real_dstrect.y = 0;
  1609     }
  1610 
  1611     if (texture->native) {
  1612         texture = texture->native;
  1613     }
  1614 
  1615     if(center) real_center = *center;
  1616     else {
  1617         real_center.x = real_dstrect.w/2;
  1618         real_center.y = real_dstrect.h/2;
  1619     }
  1620 
  1621     frect.x = real_dstrect.x * renderer->scale.x;
  1622     frect.y = real_dstrect.y * renderer->scale.y;
  1623     frect.w = real_dstrect.w * renderer->scale.x;
  1624     frect.h = real_dstrect.h * renderer->scale.y;
  1625 
  1626     fcenter.x = real_center.x * renderer->scale.x;
  1627     fcenter.y = real_center.y * renderer->scale.y;
  1628 
  1629     return renderer->RenderCopyEx(renderer, texture, &real_srcrect, &frect, angle, &fcenter, flip);
  1630 }
  1631 
  1632 int
  1633 SDL_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
  1634                      Uint32 format, void * pixels, int pitch)
  1635 {
  1636     SDL_Rect real_rect;
  1637 
  1638     CHECK_RENDERER_MAGIC(renderer, -1);
  1639 
  1640     if (!renderer->RenderReadPixels) {
  1641         return SDL_Unsupported();
  1642     }
  1643 
  1644     if (!format) {
  1645         format = SDL_GetWindowPixelFormat(renderer->window);
  1646     }
  1647 
  1648     real_rect.x = renderer->viewport.x;
  1649     real_rect.y = renderer->viewport.y;
  1650     real_rect.w = renderer->viewport.w;
  1651     real_rect.h = renderer->viewport.h;
  1652     if (rect) {
  1653         if (!SDL_IntersectRect(rect, &real_rect, &real_rect)) {
  1654             return 0;
  1655         }
  1656         if (real_rect.y > rect->y) {
  1657             pixels = (Uint8 *)pixels + pitch * (real_rect.y - rect->y);
  1658         }
  1659         if (real_rect.x > rect->x) {
  1660             int bpp = SDL_BYTESPERPIXEL(format);
  1661             pixels = (Uint8 *)pixels + bpp * (real_rect.x - rect->x);
  1662         }
  1663     }
  1664 
  1665     return renderer->RenderReadPixels(renderer, &real_rect,
  1666                                       format, pixels, pitch);
  1667 }
  1668 
  1669 void
  1670 SDL_RenderPresent(SDL_Renderer * renderer)
  1671 {
  1672     CHECK_RENDERER_MAGIC(renderer, );
  1673 
  1674     /* Don't draw while we're hidden */
  1675     if (renderer->hidden) {
  1676         return;
  1677     }
  1678     renderer->RenderPresent(renderer);
  1679 }
  1680 
  1681 void
  1682 SDL_DestroyTexture(SDL_Texture * texture)
  1683 {
  1684     SDL_Renderer *renderer;
  1685 
  1686     CHECK_TEXTURE_MAGIC(texture, );
  1687     texture->magic = NULL;
  1688 
  1689     renderer = texture->renderer;
  1690     if (texture->next) {
  1691         texture->next->prev = texture->prev;
  1692     }
  1693     if (texture->prev) {
  1694         texture->prev->next = texture->next;
  1695     } else {
  1696         renderer->textures = texture->next;
  1697     }
  1698 
  1699     if (texture->native) {
  1700         SDL_DestroyTexture(texture->native);
  1701     }
  1702     if (texture->yuv) {
  1703         SDL_SW_DestroyYUVTexture(texture->yuv);
  1704     }
  1705     if (texture->pixels) {
  1706         SDL_free(texture->pixels);
  1707     }
  1708 
  1709     renderer->DestroyTexture(renderer, texture);
  1710     SDL_free(texture);
  1711 }
  1712 
  1713 void
  1714 SDL_DestroyRenderer(SDL_Renderer * renderer)
  1715 {
  1716     CHECK_RENDERER_MAGIC(renderer, );
  1717 
  1718     SDL_DelEventWatch(SDL_RendererEventWatch, renderer);
  1719 
  1720     /* Free existing textures for this renderer */
  1721     while (renderer->textures) {
  1722         SDL_DestroyTexture(renderer->textures);
  1723     }
  1724 
  1725     if (renderer->window) {
  1726         SDL_SetWindowData(renderer->window, SDL_WINDOWRENDERDATA, NULL);
  1727     }
  1728 
  1729     /* It's no longer magical... */
  1730     renderer->magic = NULL;
  1731 
  1732     /* Free the renderer instance */
  1733     renderer->DestroyRenderer(renderer);
  1734 }
  1735 
  1736 int SDL_GL_BindTexture(SDL_Texture *texture, float *texw, float *texh)
  1737 {
  1738     SDL_Renderer *renderer;
  1739 
  1740     CHECK_TEXTURE_MAGIC(texture, -1);
  1741     renderer = texture->renderer;
  1742     if (renderer && renderer->GL_BindTexture) {
  1743         return renderer->GL_BindTexture(renderer, texture, texw, texh);
  1744     }
  1745 
  1746     return SDL_Unsupported();
  1747 }
  1748 
  1749 int SDL_GL_UnbindTexture(SDL_Texture *texture)
  1750 {
  1751     SDL_Renderer *renderer;
  1752 
  1753     CHECK_TEXTURE_MAGIC(texture, -1);
  1754     renderer = texture->renderer;
  1755     if (renderer && renderer->GL_UnbindTexture) {
  1756         return renderer->GL_UnbindTexture(renderer, texture);
  1757     }
  1758 
  1759     return SDL_Unsupported();
  1760 }
  1761 
  1762 /* vi: set ts=4 sw=4 expandtab: */