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