src/render/SDL_render.c
author David Ludwig <dludwig@pobox.com>
Thu, 28 Nov 2013 22:09:21 -0500
changeset 8543 b9dd3cf38585
parent 8535 e8ee0708ef5c
parent 7898 72af77fc6683
child 8583 fb2933ca805f
permissions -rw-r--r--
WinRT: merged with latest SDL 2.x/HG code

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