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