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