src/render/SDL_render.c
author Sam Lantinga <slouken@libsdl.org>
Sat, 16 Aug 2014 23:30:44 -0700
changeset 9078 230e7558f76a
parent 8728 c7174f961388
child 9084 a8cbb653aea4
permissions -rw-r--r--
Fixed bug 2681 - dereference a NULL pointer dst_fmt in SDL_CreateTextureFromSurface function

Nitz

In SDL_CreateTextureFromSurface:

SDL_PixelFormat *dst_fmt;
/* Set up a destination surface for the texture update */
dst_fmt = SDL_AllocFormat(format);
temp = SDL_ConvertSurface(surface, dst_fmt, 0);

Here is need of NULL check for dst_fmt because there are chances of NULL return from SDL_AllocFormat(format);
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2014 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_internal.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         SDL_assert(0 && "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_BYTESPERPIXEL(format) == 0) {
   408         SDL_SetError("Invalid texture format");
   409         return NULL;
   410     }
   411     if (SDL_ISPIXELFORMAT_INDEXED(format)) {
   412         SDL_SetError("Palettized textures are not supported");
   413         return NULL;
   414     }
   415     if (w <= 0 || h <= 0) {
   416         SDL_SetError("Texture dimensions can't be 0");
   417         return NULL;
   418     }
   419     if ((renderer->info.max_texture_width && w > renderer->info.max_texture_width) ||
   420         (renderer->info.max_texture_height && h > renderer->info.max_texture_height)) {
   421         SDL_SetError("Texture dimensions are limited to %dx%d", renderer->info.max_texture_width, renderer->info.max_texture_height);
   422         return NULL;
   423     }
   424     texture = (SDL_Texture *) SDL_calloc(1, sizeof(*texture));
   425     if (!texture) {
   426         SDL_OutOfMemory();
   427         return NULL;
   428     }
   429     texture->magic = &texture_magic;
   430     texture->format = format;
   431     texture->access = access;
   432     texture->w = w;
   433     texture->h = h;
   434     texture->r = 255;
   435     texture->g = 255;
   436     texture->b = 255;
   437     texture->a = 255;
   438     texture->renderer = renderer;
   439     texture->next = renderer->textures;
   440     if (renderer->textures) {
   441         renderer->textures->prev = texture;
   442     }
   443     renderer->textures = texture;
   444 
   445     if (IsSupportedFormat(renderer, format)) {
   446         if (renderer->CreateTexture(renderer, texture) < 0) {
   447             SDL_DestroyTexture(texture);
   448             return 0;
   449         }
   450     } else {
   451         texture->native = SDL_CreateTexture(renderer,
   452                                 GetClosestSupportedFormat(renderer, format),
   453                                 access, w, h);
   454         if (!texture->native) {
   455             SDL_DestroyTexture(texture);
   456             return NULL;
   457         }
   458 
   459         /* Swap textures to have texture before texture->native in the list */
   460         texture->native->next = texture->next;
   461         if (texture->native->next) {
   462             texture->native->next->prev = texture->native;
   463         }
   464         texture->prev = texture->native->prev;
   465         if (texture->prev) {
   466             texture->prev->next = texture;
   467         }
   468         texture->native->prev = texture;
   469         texture->next = texture->native;
   470         renderer->textures = texture;
   471 
   472         if (SDL_ISPIXELFORMAT_FOURCC(texture->format)) {
   473             texture->yuv = SDL_SW_CreateYUVTexture(format, w, h);
   474             if (!texture->yuv) {
   475                 SDL_DestroyTexture(texture);
   476                 return NULL;
   477             }
   478         } else if (access == SDL_TEXTUREACCESS_STREAMING) {
   479             /* The pitch is 4 byte aligned */
   480             texture->pitch = (((w * SDL_BYTESPERPIXEL(format)) + 3) & ~3);
   481             texture->pixels = SDL_calloc(1, texture->pitch * h);
   482             if (!texture->pixels) {
   483                 SDL_DestroyTexture(texture);
   484                 return NULL;
   485             }
   486         }
   487     }
   488     return texture;
   489 }
   490 
   491 SDL_Texture *
   492 SDL_CreateTextureFromSurface(SDL_Renderer * renderer, SDL_Surface * surface)
   493 {
   494     const SDL_PixelFormat *fmt;
   495     SDL_bool needAlpha;
   496     Uint32 i;
   497     Uint32 format;
   498     SDL_Texture *texture;
   499 
   500     CHECK_RENDERER_MAGIC(renderer, NULL);
   501 
   502     if (!surface) {
   503         SDL_SetError("SDL_CreateTextureFromSurface() passed NULL surface");
   504         return NULL;
   505     }
   506 
   507     /* See what the best texture format is */
   508     fmt = surface->format;
   509     if (fmt->Amask || SDL_GetColorKey(surface, NULL) == 0) {
   510         needAlpha = SDL_TRUE;
   511     } else {
   512         needAlpha = SDL_FALSE;
   513     }
   514     format = renderer->info.texture_formats[0];
   515     for (i = 0; i < renderer->info.num_texture_formats; ++i) {
   516         if (!SDL_ISPIXELFORMAT_FOURCC(renderer->info.texture_formats[i]) &&
   517             SDL_ISPIXELFORMAT_ALPHA(renderer->info.texture_formats[i]) == needAlpha) {
   518             format = renderer->info.texture_formats[i];
   519             break;
   520         }
   521     }
   522 
   523     texture = SDL_CreateTexture(renderer, format, SDL_TEXTUREACCESS_STATIC,
   524                                 surface->w, surface->h);
   525     if (!texture) {
   526         return NULL;
   527     }
   528 
   529     if (format == surface->format->format) {
   530         if (SDL_MUSTLOCK(surface)) {
   531             SDL_LockSurface(surface);
   532             SDL_UpdateTexture(texture, NULL, surface->pixels, surface->pitch);
   533             SDL_UnlockSurface(surface);
   534         } else {
   535             SDL_UpdateTexture(texture, NULL, surface->pixels, surface->pitch);
   536         }
   537     } else {
   538         SDL_PixelFormat *dst_fmt;
   539         SDL_Surface *temp = NULL;
   540 
   541         /* Set up a destination surface for the texture update */
   542         dst_fmt = SDL_AllocFormat(format);
   543         if (!dst_fmt) {
   544            SDL_DestroyTexture(texture);
   545            return NULL;
   546         }
   547         temp = SDL_ConvertSurface(surface, dst_fmt, 0);
   548         SDL_FreeFormat(dst_fmt);
   549         if (temp) {
   550             SDL_UpdateTexture(texture, NULL, temp->pixels, temp->pitch);
   551             SDL_FreeSurface(temp);
   552         } else {
   553             SDL_DestroyTexture(texture);
   554             return NULL;
   555         }
   556     }
   557 
   558     {
   559         Uint8 r, g, b, a;
   560         SDL_BlendMode blendMode;
   561 
   562         SDL_GetSurfaceColorMod(surface, &r, &g, &b);
   563         SDL_SetTextureColorMod(texture, r, g, b);
   564 
   565         SDL_GetSurfaceAlphaMod(surface, &a);
   566         SDL_SetTextureAlphaMod(texture, a);
   567 
   568         if (SDL_GetColorKey(surface, NULL) == 0) {
   569             /* We converted to a texture with alpha format */
   570             SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_BLEND);
   571         } else {
   572             SDL_GetSurfaceBlendMode(surface, &blendMode);
   573             SDL_SetTextureBlendMode(texture, blendMode);
   574         }
   575     }
   576     return texture;
   577 }
   578 
   579 int
   580 SDL_QueryTexture(SDL_Texture * texture, Uint32 * format, int *access,
   581                  int *w, int *h)
   582 {
   583     CHECK_TEXTURE_MAGIC(texture, -1);
   584 
   585     if (format) {
   586         *format = texture->format;
   587     }
   588     if (access) {
   589         *access = texture->access;
   590     }
   591     if (w) {
   592         *w = texture->w;
   593     }
   594     if (h) {
   595         *h = texture->h;
   596     }
   597     return 0;
   598 }
   599 
   600 int
   601 SDL_SetTextureColorMod(SDL_Texture * texture, Uint8 r, Uint8 g, Uint8 b)
   602 {
   603     SDL_Renderer *renderer;
   604 
   605     CHECK_TEXTURE_MAGIC(texture, -1);
   606 
   607     renderer = texture->renderer;
   608     if (r < 255 || g < 255 || b < 255) {
   609         texture->modMode |= SDL_TEXTUREMODULATE_COLOR;
   610     } else {
   611         texture->modMode &= ~SDL_TEXTUREMODULATE_COLOR;
   612     }
   613     texture->r = r;
   614     texture->g = g;
   615     texture->b = b;
   616     if (texture->native) {
   617         return SDL_SetTextureColorMod(texture->native, r, g, b);
   618     } else if (renderer->SetTextureColorMod) {
   619         return renderer->SetTextureColorMod(renderer, texture);
   620     } else {
   621         return 0;
   622     }
   623 }
   624 
   625 int
   626 SDL_GetTextureColorMod(SDL_Texture * texture, Uint8 * r, Uint8 * g,
   627                        Uint8 * b)
   628 {
   629     CHECK_TEXTURE_MAGIC(texture, -1);
   630 
   631     if (r) {
   632         *r = texture->r;
   633     }
   634     if (g) {
   635         *g = texture->g;
   636     }
   637     if (b) {
   638         *b = texture->b;
   639     }
   640     return 0;
   641 }
   642 
   643 int
   644 SDL_SetTextureAlphaMod(SDL_Texture * texture, Uint8 alpha)
   645 {
   646     SDL_Renderer *renderer;
   647 
   648     CHECK_TEXTURE_MAGIC(texture, -1);
   649 
   650     renderer = texture->renderer;
   651     if (alpha < 255) {
   652         texture->modMode |= SDL_TEXTUREMODULATE_ALPHA;
   653     } else {
   654         texture->modMode &= ~SDL_TEXTUREMODULATE_ALPHA;
   655     }
   656     texture->a = alpha;
   657     if (texture->native) {
   658         return SDL_SetTextureAlphaMod(texture->native, alpha);
   659     } else if (renderer->SetTextureAlphaMod) {
   660         return renderer->SetTextureAlphaMod(renderer, texture);
   661     } else {
   662         return 0;
   663     }
   664 }
   665 
   666 int
   667 SDL_GetTextureAlphaMod(SDL_Texture * texture, Uint8 * alpha)
   668 {
   669     CHECK_TEXTURE_MAGIC(texture, -1);
   670 
   671     if (alpha) {
   672         *alpha = texture->a;
   673     }
   674     return 0;
   675 }
   676 
   677 int
   678 SDL_SetTextureBlendMode(SDL_Texture * texture, SDL_BlendMode blendMode)
   679 {
   680     SDL_Renderer *renderer;
   681 
   682     CHECK_TEXTURE_MAGIC(texture, -1);
   683 
   684     renderer = texture->renderer;
   685     texture->blendMode = blendMode;
   686     if (texture->native) {
   687         return SDL_SetTextureBlendMode(texture->native, blendMode);
   688     } else if (renderer->SetTextureBlendMode) {
   689         return renderer->SetTextureBlendMode(renderer, texture);
   690     } else {
   691         return 0;
   692     }
   693 }
   694 
   695 int
   696 SDL_GetTextureBlendMode(SDL_Texture * texture, SDL_BlendMode *blendMode)
   697 {
   698     CHECK_TEXTURE_MAGIC(texture, -1);
   699 
   700     if (blendMode) {
   701         *blendMode = texture->blendMode;
   702     }
   703     return 0;
   704 }
   705 
   706 static int
   707 SDL_UpdateTextureYUV(SDL_Texture * texture, const SDL_Rect * rect,
   708                      const void *pixels, int pitch)
   709 {
   710     SDL_Texture *native = texture->native;
   711     SDL_Rect full_rect;
   712 
   713     if (SDL_SW_UpdateYUVTexture(texture->yuv, rect, pixels, pitch) < 0) {
   714         return -1;
   715     }
   716 
   717     full_rect.x = 0;
   718     full_rect.y = 0;
   719     full_rect.w = texture->w;
   720     full_rect.h = texture->h;
   721     rect = &full_rect;
   722 
   723     if (texture->access == SDL_TEXTUREACCESS_STREAMING) {
   724         /* We can lock the texture and copy to it */
   725         void *native_pixels;
   726         int native_pitch;
   727 
   728         if (SDL_LockTexture(native, rect, &native_pixels, &native_pitch) < 0) {
   729             return -1;
   730         }
   731         SDL_SW_CopyYUVToRGB(texture->yuv, rect, native->format,
   732                             rect->w, rect->h, native_pixels, native_pitch);
   733         SDL_UnlockTexture(native);
   734     } else {
   735         /* Use a temporary buffer for updating */
   736         void *temp_pixels;
   737         int temp_pitch;
   738 
   739         temp_pitch = (((rect->w * SDL_BYTESPERPIXEL(native->format)) + 3) & ~3);
   740         temp_pixels = SDL_malloc(rect->h * temp_pitch);
   741         if (!temp_pixels) {
   742             return SDL_OutOfMemory();
   743         }
   744         SDL_SW_CopyYUVToRGB(texture->yuv, rect, native->format,
   745                             rect->w, rect->h, temp_pixels, temp_pitch);
   746         SDL_UpdateTexture(native, rect, temp_pixels, temp_pitch);
   747         SDL_free(temp_pixels);
   748     }
   749     return 0;
   750 }
   751 
   752 static int
   753 SDL_UpdateTextureNative(SDL_Texture * texture, const SDL_Rect * rect,
   754                         const void *pixels, int pitch)
   755 {
   756     SDL_Texture *native = texture->native;
   757 
   758     if (texture->access == SDL_TEXTUREACCESS_STREAMING) {
   759         /* We can lock the texture and copy to it */
   760         void *native_pixels;
   761         int native_pitch;
   762 
   763         if (SDL_LockTexture(native, rect, &native_pixels, &native_pitch) < 0) {
   764             return -1;
   765         }
   766         SDL_ConvertPixels(rect->w, rect->h,
   767                           texture->format, pixels, pitch,
   768                           native->format, native_pixels, native_pitch);
   769         SDL_UnlockTexture(native);
   770     } else {
   771         /* Use a temporary buffer for updating */
   772         void *temp_pixels;
   773         int temp_pitch;
   774 
   775         temp_pitch = (((rect->w * SDL_BYTESPERPIXEL(native->format)) + 3) & ~3);
   776         temp_pixels = SDL_malloc(rect->h * temp_pitch);
   777         if (!temp_pixels) {
   778             return SDL_OutOfMemory();
   779         }
   780         SDL_ConvertPixels(rect->w, rect->h,
   781                           texture->format, pixels, pitch,
   782                           native->format, temp_pixels, temp_pitch);
   783         SDL_UpdateTexture(native, rect, temp_pixels, temp_pitch);
   784         SDL_free(temp_pixels);
   785     }
   786     return 0;
   787 }
   788 
   789 int
   790 SDL_UpdateTexture(SDL_Texture * texture, const SDL_Rect * rect,
   791                   const void *pixels, int pitch)
   792 {
   793     SDL_Renderer *renderer;
   794     SDL_Rect full_rect;
   795 
   796     CHECK_TEXTURE_MAGIC(texture, -1);
   797 
   798     if (!pixels) {
   799         return SDL_InvalidParamError("pixels");
   800     }
   801     if (!pitch) {
   802         return SDL_InvalidParamError("pitch");
   803     }
   804 
   805     if (!rect) {
   806         full_rect.x = 0;
   807         full_rect.y = 0;
   808         full_rect.w = texture->w;
   809         full_rect.h = texture->h;
   810         rect = &full_rect;
   811     }
   812 
   813     if (texture->yuv) {
   814         return SDL_UpdateTextureYUV(texture, rect, pixels, pitch);
   815     } else if (texture->native) {
   816         return SDL_UpdateTextureNative(texture, rect, pixels, pitch);
   817     } else {
   818         renderer = texture->renderer;
   819         return renderer->UpdateTexture(renderer, texture, rect, pixels, pitch);
   820     }
   821 }
   822 
   823 static int
   824 SDL_UpdateTextureYUVPlanar(SDL_Texture * texture, const SDL_Rect * rect,
   825                            const Uint8 *Yplane, int Ypitch,
   826                            const Uint8 *Uplane, int Upitch,
   827                            const Uint8 *Vplane, int Vpitch)
   828 {
   829     SDL_Texture *native = texture->native;
   830     SDL_Rect full_rect;
   831 
   832     if (SDL_SW_UpdateYUVTexturePlanar(texture->yuv, rect, Yplane, Ypitch, Uplane, Upitch, Vplane, Vpitch) < 0) {
   833         return -1;
   834     }
   835 
   836     full_rect.x = 0;
   837     full_rect.y = 0;
   838     full_rect.w = texture->w;
   839     full_rect.h = texture->h;
   840     rect = &full_rect;
   841 
   842     if (texture->access == SDL_TEXTUREACCESS_STREAMING) {
   843         /* We can lock the texture and copy to it */
   844         void *native_pixels;
   845         int native_pitch;
   846 
   847         if (SDL_LockTexture(native, rect, &native_pixels, &native_pitch) < 0) {
   848             return -1;
   849         }
   850         SDL_SW_CopyYUVToRGB(texture->yuv, rect, native->format,
   851                             rect->w, rect->h, native_pixels, native_pitch);
   852         SDL_UnlockTexture(native);
   853     } else {
   854         /* Use a temporary buffer for updating */
   855         void *temp_pixels;
   856         int temp_pitch;
   857 
   858         temp_pitch = (((rect->w * SDL_BYTESPERPIXEL(native->format)) + 3) & ~3);
   859         temp_pixels = SDL_malloc(rect->h * temp_pitch);
   860         if (!temp_pixels) {
   861             return SDL_OutOfMemory();
   862         }
   863         SDL_SW_CopyYUVToRGB(texture->yuv, rect, native->format,
   864                             rect->w, rect->h, temp_pixels, temp_pitch);
   865         SDL_UpdateTexture(native, rect, temp_pixels, temp_pitch);
   866         SDL_free(temp_pixels);
   867     }
   868     return 0;
   869 }
   870 
   871 int SDL_UpdateYUVTexture(SDL_Texture * texture, const SDL_Rect * rect,
   872                          const Uint8 *Yplane, int Ypitch,
   873                          const Uint8 *Uplane, int Upitch,
   874                          const Uint8 *Vplane, int Vpitch)
   875 {
   876     SDL_Renderer *renderer;
   877     SDL_Rect full_rect;
   878 
   879     CHECK_TEXTURE_MAGIC(texture, -1);
   880 
   881     if (!Yplane) {
   882         return SDL_InvalidParamError("Yplane");
   883     }
   884     if (!Ypitch) {
   885         return SDL_InvalidParamError("Ypitch");
   886     }
   887     if (!Uplane) {
   888         return SDL_InvalidParamError("Uplane");
   889     }
   890     if (!Upitch) {
   891         return SDL_InvalidParamError("Upitch");
   892     }
   893     if (!Vplane) {
   894         return SDL_InvalidParamError("Vplane");
   895     }
   896     if (!Vpitch) {
   897         return SDL_InvalidParamError("Vpitch");
   898     }
   899 
   900     if (texture->format != SDL_PIXELFORMAT_YV12 &&
   901         texture->format != SDL_PIXELFORMAT_IYUV) {
   902         return SDL_SetError("Texture format must by YV12 or IYUV");
   903     }
   904 
   905     if (!rect) {
   906         full_rect.x = 0;
   907         full_rect.y = 0;
   908         full_rect.w = texture->w;
   909         full_rect.h = texture->h;
   910         rect = &full_rect;
   911     }
   912 
   913     if (texture->yuv) {
   914         return SDL_UpdateTextureYUVPlanar(texture, rect, Yplane, Ypitch, Uplane, Upitch, Vplane, Vpitch);
   915     } else {
   916         SDL_assert(!texture->native);
   917         renderer = texture->renderer;
   918         SDL_assert(renderer->UpdateTextureYUV);
   919 		if (renderer->UpdateTextureYUV) {
   920 			return renderer->UpdateTextureYUV(renderer, texture, rect, Yplane, Ypitch, Uplane, Upitch, Vplane, Vpitch);
   921 		} else {
   922 			return SDL_Unsupported();
   923 		}
   924 	}
   925 }
   926 
   927 static int
   928 SDL_LockTextureYUV(SDL_Texture * texture, const SDL_Rect * rect,
   929                    void **pixels, int *pitch)
   930 {
   931     return SDL_SW_LockYUVTexture(texture->yuv, rect, pixels, pitch);
   932 }
   933 
   934 static int
   935 SDL_LockTextureNative(SDL_Texture * texture, const SDL_Rect * rect,
   936                       void **pixels, int *pitch)
   937 {
   938     texture->locked_rect = *rect;
   939     *pixels = (void *) ((Uint8 *) texture->pixels +
   940                         rect->y * texture->pitch +
   941                         rect->x * SDL_BYTESPERPIXEL(texture->format));
   942     *pitch = texture->pitch;
   943     return 0;
   944 }
   945 
   946 int
   947 SDL_LockTexture(SDL_Texture * texture, const SDL_Rect * rect,
   948                 void **pixels, int *pitch)
   949 {
   950     SDL_Renderer *renderer;
   951     SDL_Rect full_rect;
   952 
   953     CHECK_TEXTURE_MAGIC(texture, -1);
   954 
   955     if (texture->access != SDL_TEXTUREACCESS_STREAMING) {
   956         return SDL_SetError("SDL_LockTexture(): texture must be streaming");
   957     }
   958 
   959     if (!rect) {
   960         full_rect.x = 0;
   961         full_rect.y = 0;
   962         full_rect.w = texture->w;
   963         full_rect.h = texture->h;
   964         rect = &full_rect;
   965     }
   966 
   967     if (texture->yuv) {
   968         return SDL_LockTextureYUV(texture, rect, pixels, pitch);
   969     } else if (texture->native) {
   970         return SDL_LockTextureNative(texture, rect, pixels, pitch);
   971     } else {
   972         renderer = texture->renderer;
   973         return renderer->LockTexture(renderer, texture, rect, pixels, pitch);
   974     }
   975 }
   976 
   977 static void
   978 SDL_UnlockTextureYUV(SDL_Texture * texture)
   979 {
   980     SDL_Texture *native = texture->native;
   981     void *native_pixels = NULL;
   982     int native_pitch = 0;
   983     SDL_Rect rect;
   984 
   985     rect.x = 0;
   986     rect.y = 0;
   987     rect.w = texture->w;
   988     rect.h = texture->h;
   989 
   990     if (SDL_LockTexture(native, &rect, &native_pixels, &native_pitch) < 0) {
   991         return;
   992     }
   993     SDL_SW_CopyYUVToRGB(texture->yuv, &rect, native->format,
   994                         rect.w, rect.h, native_pixels, native_pitch);
   995     SDL_UnlockTexture(native);
   996 }
   997 
   998 static void
   999 SDL_UnlockTextureNative(SDL_Texture * texture)
  1000 {
  1001     SDL_Texture *native = texture->native;
  1002     void *native_pixels = NULL;
  1003     int native_pitch = 0;
  1004     const SDL_Rect *rect = &texture->locked_rect;
  1005     const void* pixels = (void *) ((Uint8 *) texture->pixels +
  1006                         rect->y * texture->pitch +
  1007                         rect->x * SDL_BYTESPERPIXEL(texture->format));
  1008     int pitch = texture->pitch;
  1009 
  1010     if (SDL_LockTexture(native, rect, &native_pixels, &native_pitch) < 0) {
  1011         return;
  1012     }
  1013     SDL_ConvertPixels(rect->w, rect->h,
  1014                       texture->format, pixels, pitch,
  1015                       native->format, native_pixels, native_pitch);
  1016     SDL_UnlockTexture(native);
  1017 }
  1018 
  1019 void
  1020 SDL_UnlockTexture(SDL_Texture * texture)
  1021 {
  1022     SDL_Renderer *renderer;
  1023 
  1024     CHECK_TEXTURE_MAGIC(texture, );
  1025 
  1026     if (texture->access != SDL_TEXTUREACCESS_STREAMING) {
  1027         return;
  1028     }
  1029     if (texture->yuv) {
  1030         SDL_UnlockTextureYUV(texture);
  1031     } else if (texture->native) {
  1032         SDL_UnlockTextureNative(texture);
  1033     } else {
  1034         renderer = texture->renderer;
  1035         renderer->UnlockTexture(renderer, texture);
  1036     }
  1037 }
  1038 
  1039 SDL_bool
  1040 SDL_RenderTargetSupported(SDL_Renderer *renderer)
  1041 {
  1042     if (!renderer || !renderer->SetRenderTarget) {
  1043         return SDL_FALSE;
  1044     }
  1045     return (renderer->info.flags & SDL_RENDERER_TARGETTEXTURE) != 0;
  1046 }
  1047 
  1048 int
  1049 SDL_SetRenderTarget(SDL_Renderer *renderer, SDL_Texture *texture)
  1050 {
  1051     if (!SDL_RenderTargetSupported(renderer)) {
  1052         return SDL_Unsupported();
  1053     }
  1054     if (texture == renderer->target) {
  1055         /* Nothing to do! */
  1056         return 0;
  1057     }
  1058 
  1059     /* texture == NULL is valid and means reset the target to the window */
  1060     if (texture) {
  1061         CHECK_TEXTURE_MAGIC(texture, -1);
  1062         if (renderer != texture->renderer) {
  1063             return SDL_SetError("Texture was not created with this renderer");
  1064         }
  1065         if (texture->access != SDL_TEXTUREACCESS_TARGET) {
  1066             return SDL_SetError("Texture not created with SDL_TEXTUREACCESS_TARGET");
  1067         }
  1068         if (texture->native) {
  1069             /* Always render to the native texture */
  1070             texture = texture->native;
  1071         }
  1072     }
  1073 
  1074     if (texture && !renderer->target) {
  1075         /* Make a backup of the viewport */
  1076         renderer->viewport_backup = renderer->viewport;
  1077         renderer->clip_rect_backup = renderer->clip_rect;
  1078         renderer->clipping_enabled_backup = renderer->clipping_enabled;
  1079         renderer->scale_backup = renderer->scale;
  1080         renderer->logical_w_backup = renderer->logical_w;
  1081         renderer->logical_h_backup = renderer->logical_h;
  1082     }
  1083     renderer->target = texture;
  1084 
  1085     if (renderer->SetRenderTarget(renderer, texture) < 0) {
  1086         return -1;
  1087     }
  1088 
  1089     if (texture) {
  1090         renderer->viewport.x = 0;
  1091         renderer->viewport.y = 0;
  1092         renderer->viewport.w = texture->w;
  1093         renderer->viewport.h = texture->h;
  1094         renderer->scale.x = 1.0f;
  1095         renderer->scale.y = 1.0f;
  1096         renderer->logical_w = texture->w;
  1097         renderer->logical_h = texture->h;
  1098     } else {
  1099         renderer->viewport = renderer->viewport_backup;
  1100         renderer->clip_rect = renderer->clip_rect_backup;
  1101         renderer->clipping_enabled = renderer->clipping_enabled_backup;
  1102         renderer->scale = renderer->scale_backup;
  1103         renderer->logical_w = renderer->logical_w_backup;
  1104         renderer->logical_h = renderer->logical_h_backup;
  1105     }
  1106     if (renderer->UpdateViewport(renderer) < 0) {
  1107         return -1;
  1108     }
  1109     if (renderer->UpdateClipRect(renderer) < 0) {
  1110         return -1;
  1111     }
  1112 
  1113     /* All set! */
  1114     return 0;
  1115 }
  1116 
  1117 SDL_Texture *
  1118 SDL_GetRenderTarget(SDL_Renderer *renderer)
  1119 {
  1120     return renderer->target;
  1121 }
  1122 
  1123 static int
  1124 UpdateLogicalSize(SDL_Renderer *renderer)
  1125 {
  1126     int w = 1, h = 1;
  1127     float want_aspect;
  1128     float real_aspect;
  1129     float scale;
  1130     SDL_Rect viewport;
  1131 
  1132     if (SDL_GetRendererOutputSize(renderer, &w, &h) < 0) {
  1133         return -1;
  1134     }
  1135 
  1136     want_aspect = (float)renderer->logical_w / renderer->logical_h;
  1137     real_aspect = (float)w / h;
  1138 
  1139     /* Clear the scale because we're setting viewport in output coordinates */
  1140     SDL_RenderSetScale(renderer, 1.0f, 1.0f);
  1141 
  1142     if (SDL_fabs(want_aspect-real_aspect) < 0.0001) {
  1143         /* The aspect ratios are the same, just scale appropriately */
  1144         scale = (float)w / renderer->logical_w;
  1145         SDL_RenderSetViewport(renderer, NULL);
  1146     } else if (want_aspect > real_aspect) {
  1147         /* We want a wider aspect ratio than is available - letterbox it */
  1148         scale = (float)w / renderer->logical_w;
  1149         viewport.x = 0;
  1150         viewport.w = w;
  1151         viewport.h = (int)SDL_ceil(renderer->logical_h * scale);
  1152         viewport.y = (h - viewport.h) / 2;
  1153         SDL_RenderSetViewport(renderer, &viewport);
  1154     } else {
  1155         /* We want a narrower aspect ratio than is available - use side-bars */
  1156         scale = (float)h / renderer->logical_h;
  1157         viewport.y = 0;
  1158         viewport.h = h;
  1159         viewport.w = (int)SDL_ceil(renderer->logical_w * scale);
  1160         viewport.x = (w - viewport.w) / 2;
  1161         SDL_RenderSetViewport(renderer, &viewport);
  1162     }
  1163 
  1164     /* Set the new scale */
  1165     SDL_RenderSetScale(renderer, scale, scale);
  1166 
  1167     return 0;
  1168 }
  1169 
  1170 int
  1171 SDL_RenderSetLogicalSize(SDL_Renderer * renderer, int w, int h)
  1172 {
  1173     CHECK_RENDERER_MAGIC(renderer, -1);
  1174 
  1175     if (!w || !h) {
  1176         /* Clear any previous logical resolution */
  1177         renderer->logical_w = 0;
  1178         renderer->logical_h = 0;
  1179         SDL_RenderSetViewport(renderer, NULL);
  1180         SDL_RenderSetScale(renderer, 1.0f, 1.0f);
  1181         return 0;
  1182     }
  1183 
  1184     renderer->logical_w = w;
  1185     renderer->logical_h = h;
  1186 
  1187     return UpdateLogicalSize(renderer);
  1188 }
  1189 
  1190 void
  1191 SDL_RenderGetLogicalSize(SDL_Renderer * renderer, int *w, int *h)
  1192 {
  1193     CHECK_RENDERER_MAGIC(renderer, );
  1194 
  1195     if (w) {
  1196         *w = renderer->logical_w;
  1197     }
  1198     if (h) {
  1199         *h = renderer->logical_h;
  1200     }
  1201 }
  1202 
  1203 int
  1204 SDL_RenderSetViewport(SDL_Renderer * renderer, const SDL_Rect * rect)
  1205 {
  1206     CHECK_RENDERER_MAGIC(renderer, -1);
  1207 
  1208     if (rect) {
  1209         renderer->viewport.x = (int)SDL_floor(rect->x * renderer->scale.x);
  1210         renderer->viewport.y = (int)SDL_floor(rect->y * renderer->scale.y);
  1211         renderer->viewport.w = (int)SDL_ceil(rect->w * renderer->scale.x);
  1212         renderer->viewport.h = (int)SDL_ceil(rect->h * renderer->scale.y);
  1213     } else {
  1214         renderer->viewport.x = 0;
  1215         renderer->viewport.y = 0;
  1216         if (SDL_GetRendererOutputSize(renderer, &renderer->viewport.w, &renderer->viewport.h) < 0) {
  1217             return -1;
  1218         }
  1219     }
  1220     return renderer->UpdateViewport(renderer);
  1221 }
  1222 
  1223 void
  1224 SDL_RenderGetViewport(SDL_Renderer * renderer, SDL_Rect * rect)
  1225 {
  1226     CHECK_RENDERER_MAGIC(renderer, );
  1227 
  1228     if (rect) {
  1229         rect->x = (int)(renderer->viewport.x / renderer->scale.x);
  1230         rect->y = (int)(renderer->viewport.y / renderer->scale.y);
  1231         rect->w = (int)(renderer->viewport.w / renderer->scale.x);
  1232         rect->h = (int)(renderer->viewport.h / renderer->scale.y);
  1233     }
  1234 }
  1235 
  1236 int
  1237 SDL_RenderSetClipRect(SDL_Renderer * renderer, const SDL_Rect * rect)
  1238 {
  1239     CHECK_RENDERER_MAGIC(renderer, -1)
  1240 
  1241     if (rect) {
  1242         renderer->clipping_enabled = SDL_TRUE;
  1243         renderer->clip_rect.x = (int)SDL_floor(rect->x * renderer->scale.x);
  1244         renderer->clip_rect.y = (int)SDL_floor(rect->y * renderer->scale.y);
  1245         renderer->clip_rect.w = (int)SDL_ceil(rect->w * renderer->scale.x);
  1246         renderer->clip_rect.h = (int)SDL_ceil(rect->h * renderer->scale.y);
  1247     } else {
  1248         renderer->clipping_enabled = SDL_FALSE;
  1249         SDL_zero(renderer->clip_rect);
  1250     }
  1251     return renderer->UpdateClipRect(renderer);
  1252 }
  1253 
  1254 void
  1255 SDL_RenderGetClipRect(SDL_Renderer * renderer, SDL_Rect * rect)
  1256 {
  1257     CHECK_RENDERER_MAGIC(renderer, )
  1258 
  1259     if (rect) {
  1260         rect->x = (int)(renderer->clip_rect.x / renderer->scale.x);
  1261         rect->y = (int)(renderer->clip_rect.y / renderer->scale.y);
  1262         rect->w = (int)(renderer->clip_rect.w / renderer->scale.x);
  1263         rect->h = (int)(renderer->clip_rect.h / renderer->scale.y);
  1264     }
  1265 }
  1266 
  1267 SDL_bool
  1268 SDL_RenderIsClipEnabled(SDL_Renderer * renderer)
  1269 {
  1270     CHECK_RENDERER_MAGIC(renderer, SDL_FALSE)
  1271     return renderer->clipping_enabled;
  1272 }
  1273 
  1274 int
  1275 SDL_RenderSetScale(SDL_Renderer * renderer, float scaleX, float scaleY)
  1276 {
  1277     CHECK_RENDERER_MAGIC(renderer, -1);
  1278 
  1279     renderer->scale.x = scaleX;
  1280     renderer->scale.y = scaleY;
  1281     return 0;
  1282 }
  1283 
  1284 void
  1285 SDL_RenderGetScale(SDL_Renderer * renderer, float *scaleX, float *scaleY)
  1286 {
  1287     CHECK_RENDERER_MAGIC(renderer, );
  1288 
  1289     if (scaleX) {
  1290         *scaleX = renderer->scale.x;
  1291     }
  1292     if (scaleY) {
  1293         *scaleY = renderer->scale.y;
  1294     }
  1295 }
  1296 
  1297 int
  1298 SDL_SetRenderDrawColor(SDL_Renderer * renderer,
  1299                        Uint8 r, Uint8 g, Uint8 b, Uint8 a)
  1300 {
  1301     CHECK_RENDERER_MAGIC(renderer, -1);
  1302 
  1303     renderer->r = r;
  1304     renderer->g = g;
  1305     renderer->b = b;
  1306     renderer->a = a;
  1307     return 0;
  1308 }
  1309 
  1310 int
  1311 SDL_GetRenderDrawColor(SDL_Renderer * renderer,
  1312                        Uint8 * r, Uint8 * g, Uint8 * b, Uint8 * a)
  1313 {
  1314     CHECK_RENDERER_MAGIC(renderer, -1);
  1315 
  1316     if (r) {
  1317         *r = renderer->r;
  1318     }
  1319     if (g) {
  1320         *g = renderer->g;
  1321     }
  1322     if (b) {
  1323         *b = renderer->b;
  1324     }
  1325     if (a) {
  1326         *a = renderer->a;
  1327     }
  1328     return 0;
  1329 }
  1330 
  1331 int
  1332 SDL_SetRenderDrawBlendMode(SDL_Renderer * renderer, SDL_BlendMode blendMode)
  1333 {
  1334     CHECK_RENDERER_MAGIC(renderer, -1);
  1335 
  1336     renderer->blendMode = blendMode;
  1337     return 0;
  1338 }
  1339 
  1340 int
  1341 SDL_GetRenderDrawBlendMode(SDL_Renderer * renderer, SDL_BlendMode *blendMode)
  1342 {
  1343     CHECK_RENDERER_MAGIC(renderer, -1);
  1344 
  1345     *blendMode = renderer->blendMode;
  1346     return 0;
  1347 }
  1348 
  1349 int
  1350 SDL_RenderClear(SDL_Renderer * renderer)
  1351 {
  1352     CHECK_RENDERER_MAGIC(renderer, -1);
  1353 
  1354     /* Don't draw while we're hidden */
  1355     if (renderer->hidden) {
  1356         return 0;
  1357     }
  1358     return renderer->RenderClear(renderer);
  1359 }
  1360 
  1361 int
  1362 SDL_RenderDrawPoint(SDL_Renderer * renderer, int x, int y)
  1363 {
  1364     SDL_Point point;
  1365 
  1366     point.x = x;
  1367     point.y = y;
  1368     return SDL_RenderDrawPoints(renderer, &point, 1);
  1369 }
  1370 
  1371 static int
  1372 RenderDrawPointsWithRects(SDL_Renderer * renderer,
  1373                      const SDL_Point * points, int count)
  1374 {
  1375     SDL_FRect *frects;
  1376     int i;
  1377     int status;
  1378 
  1379     frects = SDL_stack_alloc(SDL_FRect, count);
  1380     if (!frects) {
  1381         return SDL_OutOfMemory();
  1382     }
  1383     for (i = 0; i < count; ++i) {
  1384         frects[i].x = points[i].x * renderer->scale.x;
  1385         frects[i].y = points[i].y * renderer->scale.y;
  1386         frects[i].w = renderer->scale.x;
  1387         frects[i].h = renderer->scale.y;
  1388     }
  1389 
  1390     status = renderer->RenderFillRects(renderer, frects, count);
  1391 
  1392     SDL_stack_free(frects);
  1393 
  1394     return status;
  1395 }
  1396 
  1397 int
  1398 SDL_RenderDrawPoints(SDL_Renderer * renderer,
  1399                      const SDL_Point * points, int count)
  1400 {
  1401     SDL_FPoint *fpoints;
  1402     int i;
  1403     int status;
  1404 
  1405     CHECK_RENDERER_MAGIC(renderer, -1);
  1406 
  1407     if (!points) {
  1408         return SDL_SetError("SDL_RenderDrawPoints(): Passed NULL points");
  1409     }
  1410     if (count < 1) {
  1411         return 0;
  1412     }
  1413     /* Don't draw while we're hidden */
  1414     if (renderer->hidden) {
  1415         return 0;
  1416     }
  1417 
  1418     if (renderer->scale.x != 1.0f || renderer->scale.y != 1.0f) {
  1419         return RenderDrawPointsWithRects(renderer, points, count);
  1420     }
  1421 
  1422     fpoints = SDL_stack_alloc(SDL_FPoint, count);
  1423     if (!fpoints) {
  1424         return SDL_OutOfMemory();
  1425     }
  1426     for (i = 0; i < count; ++i) {
  1427         fpoints[i].x = points[i].x * renderer->scale.x;
  1428         fpoints[i].y = points[i].y * renderer->scale.y;
  1429     }
  1430 
  1431     status = renderer->RenderDrawPoints(renderer, fpoints, count);
  1432 
  1433     SDL_stack_free(fpoints);
  1434 
  1435     return status;
  1436 }
  1437 
  1438 int
  1439 SDL_RenderDrawLine(SDL_Renderer * renderer, int x1, int y1, int x2, int y2)
  1440 {
  1441     SDL_Point points[2];
  1442 
  1443     points[0].x = x1;
  1444     points[0].y = y1;
  1445     points[1].x = x2;
  1446     points[1].y = y2;
  1447     return SDL_RenderDrawLines(renderer, points, 2);
  1448 }
  1449 
  1450 static int
  1451 RenderDrawLinesWithRects(SDL_Renderer * renderer,
  1452                      const SDL_Point * points, int count)
  1453 {
  1454     SDL_FRect *frect;
  1455     SDL_FRect *frects;
  1456     SDL_FPoint fpoints[2];
  1457     int i, nrects;
  1458     int status;
  1459 
  1460     frects = SDL_stack_alloc(SDL_FRect, count-1);
  1461     if (!frects) {
  1462         return SDL_OutOfMemory();
  1463     }
  1464 
  1465     status = 0;
  1466     nrects = 0;
  1467     for (i = 0; i < count-1; ++i) {
  1468         if (points[i].x == points[i+1].x) {
  1469             int minY = SDL_min(points[i].y, points[i+1].y);
  1470             int maxY = SDL_max(points[i].y, points[i+1].y);
  1471 
  1472             frect = &frects[nrects++];
  1473             frect->x = points[i].x * renderer->scale.x;
  1474             frect->y = minY * renderer->scale.y;
  1475             frect->w = renderer->scale.x;
  1476             frect->h = (maxY - minY + 1) * renderer->scale.y;
  1477         } else if (points[i].y == points[i+1].y) {
  1478             int minX = SDL_min(points[i].x, points[i+1].x);
  1479             int maxX = SDL_max(points[i].x, points[i+1].x);
  1480 
  1481             frect = &frects[nrects++];
  1482             frect->x = minX * renderer->scale.x;
  1483             frect->y = points[i].y * renderer->scale.y;
  1484             frect->w = (maxX - minX + 1) * renderer->scale.x;
  1485             frect->h = renderer->scale.y;
  1486         } else {
  1487             /* FIXME: We can't use a rect for this line... */
  1488             fpoints[0].x = points[i].x * renderer->scale.x;
  1489             fpoints[0].y = points[i].y * renderer->scale.y;
  1490             fpoints[1].x = points[i+1].x * renderer->scale.x;
  1491             fpoints[1].y = points[i+1].y * renderer->scale.y;
  1492             status += renderer->RenderDrawLines(renderer, fpoints, 2);
  1493         }
  1494     }
  1495 
  1496     status += renderer->RenderFillRects(renderer, frects, nrects);
  1497 
  1498     SDL_stack_free(frects);
  1499 
  1500     if (status < 0) {
  1501         status = -1;
  1502     }
  1503     return status;
  1504 }
  1505 
  1506 int
  1507 SDL_RenderDrawLines(SDL_Renderer * renderer,
  1508                     const SDL_Point * points, int count)
  1509 {
  1510     SDL_FPoint *fpoints;
  1511     int i;
  1512     int status;
  1513 
  1514     CHECK_RENDERER_MAGIC(renderer, -1);
  1515 
  1516     if (!points) {
  1517         return SDL_SetError("SDL_RenderDrawLines(): Passed NULL points");
  1518     }
  1519     if (count < 2) {
  1520         return 0;
  1521     }
  1522     /* Don't draw while we're hidden */
  1523     if (renderer->hidden) {
  1524         return 0;
  1525     }
  1526 
  1527     if (renderer->scale.x != 1.0f || renderer->scale.y != 1.0f) {
  1528         return RenderDrawLinesWithRects(renderer, points, count);
  1529     }
  1530 
  1531     fpoints = SDL_stack_alloc(SDL_FPoint, count);
  1532     if (!fpoints) {
  1533         return SDL_OutOfMemory();
  1534     }
  1535     for (i = 0; i < count; ++i) {
  1536         fpoints[i].x = points[i].x * renderer->scale.x;
  1537         fpoints[i].y = points[i].y * renderer->scale.y;
  1538     }
  1539 
  1540     status = renderer->RenderDrawLines(renderer, fpoints, count);
  1541 
  1542     SDL_stack_free(fpoints);
  1543 
  1544     return status;
  1545 }
  1546 
  1547 int
  1548 SDL_RenderDrawRect(SDL_Renderer * renderer, const SDL_Rect * rect)
  1549 {
  1550     SDL_Rect full_rect;
  1551     SDL_Point points[5];
  1552 
  1553     CHECK_RENDERER_MAGIC(renderer, -1);
  1554 
  1555     /* If 'rect' == NULL, then outline the whole surface */
  1556     if (!rect) {
  1557         SDL_RenderGetViewport(renderer, &full_rect);
  1558         full_rect.x = 0;
  1559         full_rect.y = 0;
  1560         rect = &full_rect;
  1561     }
  1562 
  1563     points[0].x = rect->x;
  1564     points[0].y = rect->y;
  1565     points[1].x = rect->x+rect->w-1;
  1566     points[1].y = rect->y;
  1567     points[2].x = rect->x+rect->w-1;
  1568     points[2].y = rect->y+rect->h-1;
  1569     points[3].x = rect->x;
  1570     points[3].y = rect->y+rect->h-1;
  1571     points[4].x = rect->x;
  1572     points[4].y = rect->y;
  1573     return SDL_RenderDrawLines(renderer, points, 5);
  1574 }
  1575 
  1576 int
  1577 SDL_RenderDrawRects(SDL_Renderer * renderer,
  1578                     const SDL_Rect * rects, int count)
  1579 {
  1580     int i;
  1581 
  1582     CHECK_RENDERER_MAGIC(renderer, -1);
  1583 
  1584     if (!rects) {
  1585         return SDL_SetError("SDL_RenderDrawRects(): Passed NULL rects");
  1586     }
  1587     if (count < 1) {
  1588         return 0;
  1589     }
  1590 
  1591     /* Don't draw while we're hidden */
  1592     if (renderer->hidden) {
  1593         return 0;
  1594     }
  1595     for (i = 0; i < count; ++i) {
  1596         if (SDL_RenderDrawRect(renderer, &rects[i]) < 0) {
  1597             return -1;
  1598         }
  1599     }
  1600     return 0;
  1601 }
  1602 
  1603 int
  1604 SDL_RenderFillRect(SDL_Renderer * renderer, const SDL_Rect * rect)
  1605 {
  1606     SDL_Rect full_rect = { 0, 0, 0, 0 };
  1607 
  1608     CHECK_RENDERER_MAGIC(renderer, -1);
  1609 
  1610     /* If 'rect' == NULL, then outline the whole surface */
  1611     if (!rect) {
  1612         SDL_RenderGetViewport(renderer, &full_rect);
  1613         full_rect.x = 0;
  1614         full_rect.y = 0;
  1615         rect = &full_rect;
  1616     }
  1617     return SDL_RenderFillRects(renderer, rect, 1);
  1618 }
  1619 
  1620 int
  1621 SDL_RenderFillRects(SDL_Renderer * renderer,
  1622                     const SDL_Rect * rects, int count)
  1623 {
  1624     SDL_FRect *frects;
  1625     int i;
  1626     int status;
  1627 
  1628     CHECK_RENDERER_MAGIC(renderer, -1);
  1629 
  1630     if (!rects) {
  1631         return SDL_SetError("SDL_RenderFillRects(): Passed NULL rects");
  1632     }
  1633     if (count < 1) {
  1634         return 0;
  1635     }
  1636     /* Don't draw while we're hidden */
  1637     if (renderer->hidden) {
  1638         return 0;
  1639     }
  1640 
  1641     frects = SDL_stack_alloc(SDL_FRect, count);
  1642     if (!frects) {
  1643         return SDL_OutOfMemory();
  1644     }
  1645     for (i = 0; i < count; ++i) {
  1646         frects[i].x = rects[i].x * renderer->scale.x;
  1647         frects[i].y = rects[i].y * renderer->scale.y;
  1648         frects[i].w = rects[i].w * renderer->scale.x;
  1649         frects[i].h = rects[i].h * renderer->scale.y;
  1650     }
  1651 
  1652     status = renderer->RenderFillRects(renderer, frects, count);
  1653 
  1654     SDL_stack_free(frects);
  1655 
  1656     return status;
  1657 }
  1658 
  1659 int
  1660 SDL_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
  1661                const SDL_Rect * srcrect, const SDL_Rect * dstrect)
  1662 {
  1663     SDL_Rect real_srcrect = { 0, 0, 0, 0 };
  1664     SDL_Rect real_dstrect = { 0, 0, 0, 0 };
  1665     SDL_FRect frect;
  1666 
  1667     CHECK_RENDERER_MAGIC(renderer, -1);
  1668     CHECK_TEXTURE_MAGIC(texture, -1);
  1669 
  1670     if (renderer != texture->renderer) {
  1671         return SDL_SetError("Texture was not created with this renderer");
  1672     }
  1673 
  1674     real_srcrect.x = 0;
  1675     real_srcrect.y = 0;
  1676     real_srcrect.w = texture->w;
  1677     real_srcrect.h = texture->h;
  1678     if (srcrect) {
  1679         if (!SDL_IntersectRect(srcrect, &real_srcrect, &real_srcrect)) {
  1680             return 0;
  1681         }
  1682     }
  1683 
  1684     SDL_RenderGetViewport(renderer, &real_dstrect);
  1685     real_dstrect.x = 0;
  1686     real_dstrect.y = 0;
  1687     if (dstrect) {
  1688         if (!SDL_HasIntersection(dstrect, &real_dstrect)) {
  1689             return 0;
  1690         }
  1691         real_dstrect = *dstrect;
  1692     }
  1693 
  1694     if (texture->native) {
  1695         texture = texture->native;
  1696     }
  1697 
  1698     /* Don't draw while we're hidden */
  1699     if (renderer->hidden) {
  1700         return 0;
  1701     }
  1702 
  1703     frect.x = real_dstrect.x * renderer->scale.x;
  1704     frect.y = real_dstrect.y * renderer->scale.y;
  1705     frect.w = real_dstrect.w * renderer->scale.x;
  1706     frect.h = real_dstrect.h * renderer->scale.y;
  1707 
  1708     return renderer->RenderCopy(renderer, texture, &real_srcrect, &frect);
  1709 }
  1710 
  1711 
  1712 int
  1713 SDL_RenderCopyEx(SDL_Renderer * renderer, SDL_Texture * texture,
  1714                const SDL_Rect * srcrect, const SDL_Rect * dstrect,
  1715                const double angle, const SDL_Point *center, const SDL_RendererFlip flip)
  1716 {
  1717     SDL_Rect real_srcrect = { 0, 0, 0, 0 };
  1718     SDL_Rect real_dstrect = { 0, 0, 0, 0 };
  1719     SDL_Point real_center;
  1720     SDL_FRect frect;
  1721     SDL_FPoint fcenter;
  1722 
  1723     CHECK_RENDERER_MAGIC(renderer, -1);
  1724     CHECK_TEXTURE_MAGIC(texture, -1);
  1725 
  1726     if (renderer != texture->renderer) {
  1727         return SDL_SetError("Texture was not created with this renderer");
  1728     }
  1729     if (!renderer->RenderCopyEx) {
  1730         return SDL_SetError("Renderer does not support RenderCopyEx");
  1731     }
  1732 
  1733     real_srcrect.x = 0;
  1734     real_srcrect.y = 0;
  1735     real_srcrect.w = texture->w;
  1736     real_srcrect.h = texture->h;
  1737     if (srcrect) {
  1738         if (!SDL_IntersectRect(srcrect, &real_srcrect, &real_srcrect)) {
  1739             return 0;
  1740         }
  1741     }
  1742 
  1743     /* We don't intersect the dstrect with the viewport as RenderCopy does because of potential rotation clipping issues... TODO: should we? */
  1744     if (dstrect) {
  1745         real_dstrect = *dstrect;
  1746     } else {
  1747         SDL_RenderGetViewport(renderer, &real_dstrect);
  1748         real_dstrect.x = 0;
  1749         real_dstrect.y = 0;
  1750     }
  1751 
  1752     if (texture->native) {
  1753         texture = texture->native;
  1754     }
  1755 
  1756     if(center) real_center = *center;
  1757     else {
  1758         real_center.x = real_dstrect.w/2;
  1759         real_center.y = real_dstrect.h/2;
  1760     }
  1761 
  1762     frect.x = real_dstrect.x * renderer->scale.x;
  1763     frect.y = real_dstrect.y * renderer->scale.y;
  1764     frect.w = real_dstrect.w * renderer->scale.x;
  1765     frect.h = real_dstrect.h * renderer->scale.y;
  1766 
  1767     fcenter.x = real_center.x * renderer->scale.x;
  1768     fcenter.y = real_center.y * renderer->scale.y;
  1769 
  1770     return renderer->RenderCopyEx(renderer, texture, &real_srcrect, &frect, angle, &fcenter, flip);
  1771 }
  1772 
  1773 int
  1774 SDL_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
  1775                      Uint32 format, void * pixels, int pitch)
  1776 {
  1777     SDL_Rect real_rect;
  1778 
  1779     CHECK_RENDERER_MAGIC(renderer, -1);
  1780 
  1781     if (!renderer->RenderReadPixels) {
  1782         return SDL_Unsupported();
  1783     }
  1784 
  1785     if (!format) {
  1786         format = SDL_GetWindowPixelFormat(renderer->window);
  1787     }
  1788 
  1789     real_rect.x = renderer->viewport.x;
  1790     real_rect.y = renderer->viewport.y;
  1791     real_rect.w = renderer->viewport.w;
  1792     real_rect.h = renderer->viewport.h;
  1793     if (rect) {
  1794         if (!SDL_IntersectRect(rect, &real_rect, &real_rect)) {
  1795             return 0;
  1796         }
  1797         if (real_rect.y > rect->y) {
  1798             pixels = (Uint8 *)pixels + pitch * (real_rect.y - rect->y);
  1799         }
  1800         if (real_rect.x > rect->x) {
  1801             int bpp = SDL_BYTESPERPIXEL(format);
  1802             pixels = (Uint8 *)pixels + bpp * (real_rect.x - rect->x);
  1803         }
  1804     }
  1805 
  1806     return renderer->RenderReadPixels(renderer, &real_rect,
  1807                                       format, pixels, pitch);
  1808 }
  1809 
  1810 void
  1811 SDL_RenderPresent(SDL_Renderer * renderer)
  1812 {
  1813     CHECK_RENDERER_MAGIC(renderer, );
  1814 
  1815     /* Don't draw while we're hidden */
  1816     if (renderer->hidden) {
  1817         return;
  1818     }
  1819     renderer->RenderPresent(renderer);
  1820 }
  1821 
  1822 void
  1823 SDL_DestroyTexture(SDL_Texture * texture)
  1824 {
  1825     SDL_Renderer *renderer;
  1826 
  1827     CHECK_TEXTURE_MAGIC(texture, );
  1828 
  1829     renderer = texture->renderer;
  1830     if (texture == renderer->target) {
  1831         SDL_SetRenderTarget(renderer, NULL);
  1832     }
  1833 
  1834     texture->magic = NULL;
  1835 
  1836     if (texture->next) {
  1837         texture->next->prev = texture->prev;
  1838     }
  1839     if (texture->prev) {
  1840         texture->prev->next = texture->next;
  1841     } else {
  1842         renderer->textures = texture->next;
  1843     }
  1844 
  1845     if (texture->native) {
  1846         SDL_DestroyTexture(texture->native);
  1847     }
  1848     if (texture->yuv) {
  1849         SDL_SW_DestroyYUVTexture(texture->yuv);
  1850     }
  1851     SDL_free(texture->pixels);
  1852 
  1853     renderer->DestroyTexture(renderer, texture);
  1854     SDL_free(texture);
  1855 }
  1856 
  1857 void
  1858 SDL_DestroyRenderer(SDL_Renderer * renderer)
  1859 {
  1860     CHECK_RENDERER_MAGIC(renderer, );
  1861 
  1862     SDL_DelEventWatch(SDL_RendererEventWatch, renderer);
  1863 
  1864     /* Free existing textures for this renderer */
  1865     while (renderer->textures) {
  1866         SDL_DestroyTexture(renderer->textures);
  1867     }
  1868 
  1869     if (renderer->window) {
  1870         SDL_SetWindowData(renderer->window, SDL_WINDOWRENDERDATA, NULL);
  1871     }
  1872 
  1873     /* It's no longer magical... */
  1874     renderer->magic = NULL;
  1875 
  1876     /* Free the renderer instance */
  1877     renderer->DestroyRenderer(renderer);
  1878 }
  1879 
  1880 int SDL_GL_BindTexture(SDL_Texture *texture, float *texw, float *texh)
  1881 {
  1882     SDL_Renderer *renderer;
  1883 
  1884     CHECK_TEXTURE_MAGIC(texture, -1);
  1885     renderer = texture->renderer;
  1886     if (texture->native) {
  1887         return SDL_GL_BindTexture(texture->native, texw, texh);
  1888     } else if (renderer && renderer->GL_BindTexture) {
  1889         return renderer->GL_BindTexture(renderer, texture, texw, texh);
  1890     } else {
  1891         return SDL_Unsupported();
  1892     }
  1893 }
  1894 
  1895 int SDL_GL_UnbindTexture(SDL_Texture *texture)
  1896 {
  1897     SDL_Renderer *renderer;
  1898 
  1899     CHECK_TEXTURE_MAGIC(texture, -1);
  1900     renderer = texture->renderer;
  1901     if (texture->native) {
  1902         return SDL_GL_UnbindTexture(texture->native);
  1903     } else if (renderer && renderer->GL_UnbindTexture) {
  1904         return renderer->GL_UnbindTexture(renderer, texture);
  1905     }
  1906 
  1907     return SDL_Unsupported();
  1908 }
  1909 
  1910 /* vi: set ts=4 sw=4 expandtab: */