src/render/SDL_render.c
author Sam Lantinga <slouken@libsdl.org>
Sun, 21 Jul 2013 12:54:27 -0700
changeset 7496 13dfa871f0af
parent 7419 a22566f42281
child 7508 1f64c6874619
permissions -rw-r--r--
Fixed bug 1813 - MouseMotion relative values do not respect renderer LogicalSize

driedfruit

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