src/render/SDL_render.c
author Sam Lantinga <slouken@libsdl.org>
Wed, 02 Feb 2011 14:34:54 -0800
changeset 5154 fb424691cfc7
child 5156 307ccc9c135e
permissions -rw-r--r--
Moved the rendering code out to a separate directory in the hope that it can someday be completely decoupled from the rest of the library and be expanded to an awesome 2D on 3D library.
     1 /*
     2     SDL - Simple DirectMedia Layer
     3     Copyright (C) 1997-2010 Sam Lantinga
     4 
     5     This library is free software; you can redistribute it and/or
     6     modify it under the terms of the GNU Lesser General Public
     7     License as published by the Free Software Foundation; either
     8     version 2.1 of the License, or (at your option) any later version.
     9 
    10     This library is distributed in the hope that it will be useful,
    11     but WITHOUT ANY WARRANTY; without even the implied warranty of
    12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    13     Lesser General Public License for more details.
    14 
    15     You should have received a copy of the GNU Lesser General Public
    16     License along with this library; if not, write to the Free Software
    17     Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
    18 
    19     Sam Lantinga
    20     slouken@libsdl.org
    21 */
    22 #include "SDL_config.h"
    23 
    24 /* The SDL 2D rendering system */
    25 
    26 #include "SDL_render.h"
    27 #include "SDL_sysrender.h"
    28 #include "../video/SDL_pixels_c.h"
    29 
    30 
    31 #define CHECK_RENDERER_MAGIC(renderer, retval) \
    32     if (!renderer || renderer->magic != &renderer_magic) { \
    33         SDL_SetError("Invalid renderer"); \
    34         return retval; \
    35     }
    36 
    37 #define CHECK_TEXTURE_MAGIC(texture, retval) \
    38     if (!texture || texture->magic != &texture_magic) { \
    39         SDL_SetError("Invalid texture"); \
    40         return retval; \
    41     }
    42 
    43 
    44 static const SDL_RenderDriver *render_drivers[] = {
    45 #if SDL_VIDEO_RENDER_D3D
    46     &D3D_RenderDriver,
    47 #endif
    48 #if SDL_VIDEO_RENDER_OGL
    49     &GL_RenderDriver,
    50 #endif
    51 #if SDL_VIDEO_RENDER_OGL_ES
    52     &GL_ES_RenderDriver,
    53 #endif
    54     &SW_RenderDriver
    55 };
    56 static char renderer_magic;
    57 static char texture_magic;
    58 
    59 int
    60 SDL_GetNumRenderDrivers(void)
    61 {
    62     return SDL_arraysize(render_drivers);
    63 }
    64 
    65 int
    66 SDL_GetRenderDriverInfo(int index, SDL_RendererInfo * info)
    67 {
    68     if (index < 0 || index >= SDL_GetNumRenderDrivers()) {
    69         SDL_SetError("index must be in the range of 0 - %d",
    70                      SDL_GetNumRenderDrivers() - 1);
    71         return -1;
    72     }
    73     *info = render_drivers[index]->info;
    74     return 0;
    75 }
    76 
    77 static int
    78 SDL_RendererEventWatch(void *userdata, SDL_Event *event)
    79 {
    80     SDL_Renderer *renderer = (SDL_Renderer *)userdata;
    81 
    82     if (event->type == SDL_WINDOWEVENT && renderer->WindowEvent) {
    83         SDL_Window *window = SDL_GetWindowFromID(event->window.windowID);
    84         if (window == renderer->window) {
    85             renderer->WindowEvent(renderer, &event->window);
    86         }
    87     }
    88     return 0;
    89 }
    90 
    91 SDL_Renderer *
    92 SDL_CreateRenderer(SDL_Window * window, int index, Uint32 flags)
    93 {
    94     SDL_Renderer *renderer = NULL;
    95     int n = SDL_GetNumRenderDrivers();
    96 
    97     if (index < 0) {
    98         char *override = SDL_getenv("SDL_VIDEO_RENDERER");
    99 
   100         if (override) {
   101             for (index = 0; index < n; ++index) {
   102                 const SDL_RenderDriver *driver = render_drivers[index];
   103 
   104                 if (SDL_strcasecmp(override, driver->info.name) == 0) {
   105                     /* Create a new renderer instance */
   106                     renderer = driver->CreateRenderer(window, flags);
   107                     break;
   108                 }
   109             }
   110         } else {
   111             for (index = 0; index < n; ++index) {
   112                 const SDL_RenderDriver *driver = render_drivers[index];
   113 
   114                 if ((driver->info.flags & flags) == flags) {
   115                     /* Create a new renderer instance */
   116                     renderer = driver->CreateRenderer(window, flags);
   117                     if (renderer) {
   118                         /* Yay, we got one! */
   119                         break;
   120                     }
   121                 }
   122             }
   123         }
   124         if (index == n) {
   125             SDL_SetError("Couldn't find matching render driver");
   126             return NULL;
   127         }
   128     } else {
   129         if (index >= SDL_GetNumRenderDrivers()) {
   130             SDL_SetError("index must be -1 or in the range of 0 - %d",
   131                          SDL_GetNumRenderDrivers() - 1);
   132             return NULL;
   133         }
   134         /* Create a new renderer instance */
   135         renderer = render_drivers[index]->CreateRenderer(window, flags);
   136     }
   137 
   138     if (renderer) {
   139         renderer->magic = &renderer_magic;
   140 
   141         SDL_AddEventWatch(SDL_RendererEventWatch, renderer);
   142     }
   143     return renderer;
   144 }
   145 
   146 int
   147 SDL_GetRendererInfo(SDL_Renderer * renderer, SDL_RendererInfo * info)
   148 {
   149     CHECK_RENDERER_MAGIC(renderer, -1);
   150 
   151     *info = renderer->info;
   152     return 0;
   153 }
   154 
   155 SDL_Texture *
   156 SDL_CreateTexture(SDL_Renderer * renderer, Uint32 format, int access, int w, int h)
   157 {
   158     SDL_Texture *texture;
   159 
   160     CHECK_RENDERER_MAGIC(renderer, NULL);
   161 
   162     if (w <= 0 || h <= 0) {
   163         SDL_SetError("Texture dimensions can't be 0");
   164         return 0;
   165     }
   166     texture = (SDL_Texture *) SDL_calloc(1, sizeof(*texture));
   167     if (!texture) {
   168         SDL_OutOfMemory();
   169         return 0;
   170     }
   171     texture->magic = &texture_magic;
   172     texture->format = format;
   173     texture->access = access;
   174     texture->w = w;
   175     texture->h = h;
   176     texture->r = 255;
   177     texture->g = 255;
   178     texture->b = 255;
   179     texture->a = 255;
   180     texture->renderer = renderer;
   181     texture->next = renderer->textures;
   182     if (renderer->textures) {
   183         renderer->textures->prev = texture;
   184     }
   185     renderer->textures = texture;
   186 
   187     if (renderer->CreateTexture(renderer, texture) < 0) {
   188         SDL_DestroyTexture(texture);
   189         return 0;
   190     }
   191     return texture;
   192 }
   193 
   194 SDL_Texture *
   195 SDL_CreateTextureFromSurface(SDL_Renderer * renderer, Uint32 format, SDL_Surface * surface)
   196 {
   197     SDL_Texture *texture;
   198     Uint32 requested_format = format;
   199     SDL_PixelFormat *fmt;
   200     int bpp;
   201     Uint32 Rmask, Gmask, Bmask, Amask;
   202 
   203     CHECK_RENDERER_MAGIC(renderer, NULL);
   204 
   205     if (!surface) {
   206         SDL_SetError("SDL_CreateTextureFromSurface() passed NULL surface");
   207         return NULL;
   208     }
   209     fmt = surface->format;
   210 
   211     if (format) {
   212         if (!SDL_PixelFormatEnumToMasks
   213             (format, &bpp, &Rmask, &Gmask, &Bmask, &Amask)) {
   214             SDL_SetError("Unknown pixel format");
   215             return 0;
   216         }
   217     } else {
   218         SDL_bool hasColorkey;
   219         SDL_BlendMode blendMode;
   220         SDL_bool hasBlending;
   221 
   222         hasColorkey = (SDL_GetColorKey(surface, NULL) == 0);
   223 
   224         SDL_GetSurfaceBlendMode(surface, &blendMode);
   225         hasBlending = (blendMode == SDL_BLENDMODE_BLEND);
   226 
   227         if (surface->format->Amask || (!hasColorkey && !hasBlending)) {
   228             Uint32 it;
   229             int pfmt;
   230 
   231             /* Pixel formats, sorted by best first */
   232             static const Uint32 sdl_pformats[] = {
   233                 SDL_PIXELFORMAT_ARGB8888,
   234                 SDL_PIXELFORMAT_RGBA8888,
   235                 SDL_PIXELFORMAT_ABGR8888,
   236                 SDL_PIXELFORMAT_BGRA8888,
   237                 SDL_PIXELFORMAT_RGB888,
   238                 SDL_PIXELFORMAT_BGR888,
   239                 SDL_PIXELFORMAT_RGB24,
   240                 SDL_PIXELFORMAT_BGR24,
   241                 SDL_PIXELFORMAT_RGB565,
   242                 SDL_PIXELFORMAT_BGR565,
   243                 SDL_PIXELFORMAT_ARGB1555,
   244                 SDL_PIXELFORMAT_RGBA5551,
   245                 SDL_PIXELFORMAT_ABGR1555,
   246                 SDL_PIXELFORMAT_BGRA5551,
   247                 SDL_PIXELFORMAT_RGB555,
   248                 SDL_PIXELFORMAT_BGR555,
   249                 SDL_PIXELFORMAT_ARGB4444,
   250                 SDL_PIXELFORMAT_RGBA4444,
   251                 SDL_PIXELFORMAT_ABGR4444,
   252                 SDL_PIXELFORMAT_BGRA4444,
   253                 SDL_PIXELFORMAT_RGB444,
   254                 SDL_PIXELFORMAT_ARGB2101010,
   255                 SDL_PIXELFORMAT_RGB332,
   256                 SDL_PIXELFORMAT_UNKNOWN
   257             };
   258 
   259             bpp = fmt->BitsPerPixel;
   260             Rmask = fmt->Rmask;
   261             Gmask = fmt->Gmask;
   262             Bmask = fmt->Bmask;
   263             Amask = fmt->Amask;
   264 
   265             format =
   266                 SDL_MasksToPixelFormatEnum(bpp, Rmask, Gmask, Bmask, Amask);
   267             if (!format) {
   268                 SDL_SetError("Unknown pixel format");
   269                 return 0;
   270             }
   271 
   272             /* Search requested format in the supported texture */
   273             /* formats by current renderer                      */
   274             for (it = 0; it < renderer->info.num_texture_formats; it++) {
   275                 if (renderer->info.texture_formats[it] == format) {
   276                     break;
   277                 }
   278             }
   279 
   280             /* If requested format can't be found, search any best */
   281             /* format which renderer provides                      */
   282             if (it == renderer->info.num_texture_formats) {
   283                 pfmt = 0;
   284                 for (;;) {
   285                     if (sdl_pformats[pfmt] == SDL_PIXELFORMAT_UNKNOWN) {
   286                         break;
   287                     }
   288 
   289                     for (it = 0; it < renderer->info.num_texture_formats;
   290                          it++) {
   291                         if (renderer->info.texture_formats[it] ==
   292                             sdl_pformats[pfmt]) {
   293                             break;
   294                         }
   295                     }
   296 
   297                     if (it != renderer->info.num_texture_formats) {
   298                         /* The best format has been found */
   299                         break;
   300                     }
   301                     pfmt++;
   302                 }
   303 
   304                 /* If any format can't be found, then return an error */
   305                 if (it == renderer->info.num_texture_formats) {
   306                     SDL_SetError
   307                         ("Any of the supported pixel formats can't be found");
   308                     return 0;
   309                 }
   310 
   311                 /* Convert found pixel format back to color masks */
   312                 if (SDL_PixelFormatEnumToMasks
   313                     (renderer->info.texture_formats[it], &bpp, &Rmask, &Gmask,
   314                      &Bmask, &Amask) != SDL_TRUE) {
   315                     SDL_SetError("Unknown pixel format");
   316                     return 0;
   317                 }
   318             }
   319         } else {
   320             /* Need a format with alpha */
   321             Uint32 it;
   322             int apfmt;
   323 
   324             /* Pixel formats with alpha, sorted by best first */
   325             static const Uint32 sdl_alpha_pformats[] = {
   326                 SDL_PIXELFORMAT_ARGB8888,
   327                 SDL_PIXELFORMAT_RGBA8888,
   328                 SDL_PIXELFORMAT_ABGR8888,
   329                 SDL_PIXELFORMAT_BGRA8888,
   330                 SDL_PIXELFORMAT_ARGB1555,
   331                 SDL_PIXELFORMAT_RGBA5551,
   332                 SDL_PIXELFORMAT_ABGR1555,
   333                 SDL_PIXELFORMAT_BGRA5551,
   334                 SDL_PIXELFORMAT_ARGB4444,
   335                 SDL_PIXELFORMAT_RGBA4444,
   336                 SDL_PIXELFORMAT_ABGR4444,
   337                 SDL_PIXELFORMAT_BGRA4444,
   338                 SDL_PIXELFORMAT_ARGB2101010,
   339                 SDL_PIXELFORMAT_UNKNOWN
   340             };
   341 
   342             if (surface->format->Amask) {
   343                 /* If surface already has alpha, then try an original */
   344                 /* surface format first                               */
   345                 bpp = fmt->BitsPerPixel;
   346                 Rmask = fmt->Rmask;
   347                 Gmask = fmt->Gmask;
   348                 Bmask = fmt->Bmask;
   349                 Amask = fmt->Amask;
   350             } else {
   351                 bpp = 32;
   352                 Rmask = 0x00FF0000;
   353                 Gmask = 0x0000FF00;
   354                 Bmask = 0x000000FF;
   355                 Amask = 0xFF000000;
   356             }
   357 
   358             format =
   359                 SDL_MasksToPixelFormatEnum(bpp, Rmask, Gmask, Bmask, Amask);
   360             if (!format) {
   361                 SDL_SetError("Unknown pixel format");
   362                 return 0;
   363             }
   364 
   365             /* Search this format in the supported texture formats */
   366             /* by current renderer                                 */
   367             for (it = 0; it < renderer->info.num_texture_formats; it++) {
   368                 if (renderer->info.texture_formats[it] == format) {
   369                     break;
   370                 }
   371             }
   372 
   373             /* If this format can't be found, search any best       */
   374             /* compatible format with alpha which renderer provides */
   375             if (it == renderer->info.num_texture_formats) {
   376                 apfmt = 0;
   377                 for (;;) {
   378                     if (sdl_alpha_pformats[apfmt] == SDL_PIXELFORMAT_UNKNOWN) {
   379                         break;
   380                     }
   381 
   382                     for (it = 0; it < renderer->info.num_texture_formats;
   383                          it++) {
   384                         if (renderer->info.texture_formats[it] ==
   385                             sdl_alpha_pformats[apfmt]) {
   386                             break;
   387                         }
   388                     }
   389 
   390                     if (it != renderer->info.num_texture_formats) {
   391                         /* Compatible format has been found */
   392                         break;
   393                     }
   394                     apfmt++;
   395                 }
   396 
   397                 /* If compatible format can't be found, then return an error */
   398                 if (it == renderer->info.num_texture_formats) {
   399                     SDL_SetError("Compatible pixel format can't be found");
   400                     return 0;
   401                 }
   402 
   403                 /* Convert found pixel format back to color masks */
   404                 if (SDL_PixelFormatEnumToMasks
   405                     (renderer->info.texture_formats[it], &bpp, &Rmask, &Gmask,
   406                      &Bmask, &Amask) != SDL_TRUE) {
   407                     SDL_SetError("Unknown pixel format");
   408                     return 0;
   409                 }
   410             }
   411         }
   412 
   413         format = SDL_MasksToPixelFormatEnum(bpp, Rmask, Gmask, Bmask, Amask);
   414         if (!format) {
   415             SDL_SetError("Unknown pixel format");
   416             return 0;
   417         }
   418     }
   419 
   420     texture =
   421         SDL_CreateTexture(renderer, format, SDL_TEXTUREACCESS_STATIC,
   422                           surface->w, surface->h);
   423     if (!texture && !requested_format) {
   424         SDL_DisplayMode desktop_mode;
   425         SDL_GetDesktopDisplayMode(&desktop_mode);
   426         format = desktop_mode.format;
   427         texture = SDL_CreateTexture(renderer, format, SDL_TEXTUREACCESS_STATIC,
   428                                     surface->w, surface->h);
   429     }
   430     if (!texture) {
   431         return 0;
   432     }
   433     if (bpp == fmt->BitsPerPixel && Rmask == fmt->Rmask && Gmask == fmt->Gmask
   434         && Bmask == fmt->Bmask && Amask == fmt->Amask) {
   435         if (SDL_MUSTLOCK(surface)) {
   436             SDL_LockSurface(surface);
   437             SDL_UpdateTexture(texture, NULL, surface->pixels,
   438                               surface->pitch);
   439             SDL_UnlockSurface(surface);
   440         } else {
   441             SDL_UpdateTexture(texture, NULL, surface->pixels,
   442                               surface->pitch);
   443         }
   444     } else {
   445         SDL_PixelFormat dst_fmt;
   446         SDL_Surface *dst = NULL;
   447 
   448         /* Set up a destination surface for the texture update */
   449         SDL_InitFormat(&dst_fmt, bpp, Rmask, Gmask, Bmask, Amask);
   450         dst = SDL_ConvertSurface(surface, &dst_fmt, 0);
   451         if (dst) {
   452             SDL_UpdateTexture(texture, NULL, dst->pixels, dst->pitch);
   453             SDL_FreeSurface(dst);
   454         }
   455         if (!dst) {
   456             SDL_DestroyTexture(texture);
   457             return 0;
   458         }
   459     }
   460 
   461     {
   462         Uint8 r, g, b, a;
   463         SDL_BlendMode blendMode;
   464 
   465         SDL_GetSurfaceColorMod(surface, &r, &g, &b);
   466         SDL_SetTextureColorMod(texture, r, g, b);
   467 
   468         SDL_GetSurfaceAlphaMod(surface, &a);
   469         SDL_SetTextureAlphaMod(texture, a);
   470 
   471         if (SDL_GetColorKey(surface, NULL) == 0) {
   472             /* We converted to a texture with alpha format */
   473             SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_BLEND);
   474         } else {
   475             SDL_GetSurfaceBlendMode(surface, &blendMode);
   476             SDL_SetTextureBlendMode(texture, blendMode);
   477         }
   478     }
   479     return texture;
   480 }
   481 
   482 int
   483 SDL_QueryTexture(SDL_Texture * texture, Uint32 * format, int *access,
   484                  int *w, int *h)
   485 {
   486     CHECK_TEXTURE_MAGIC(texture, -1);
   487 
   488     if (format) {
   489         *format = texture->format;
   490     }
   491     if (access) {
   492         *access = texture->access;
   493     }
   494     if (w) {
   495         *w = texture->w;
   496     }
   497     if (h) {
   498         *h = texture->h;
   499     }
   500     return 0;
   501 }
   502 
   503 int
   504 SDL_QueryTexturePixels(SDL_Texture * texture, void **pixels, int *pitch)
   505 {
   506     SDL_Renderer *renderer;
   507 
   508     CHECK_TEXTURE_MAGIC(texture, -1);
   509 
   510     renderer = texture->renderer;
   511     if (!renderer->QueryTexturePixels) {
   512         SDL_Unsupported();
   513         return -1;
   514     }
   515     return renderer->QueryTexturePixels(renderer, texture, pixels, pitch);
   516 }
   517 
   518 int
   519 SDL_SetTextureColorMod(SDL_Texture * texture, Uint8 r, Uint8 g, Uint8 b)
   520 {
   521     SDL_Renderer *renderer;
   522 
   523     CHECK_TEXTURE_MAGIC(texture, -1);
   524 
   525     renderer = texture->renderer;
   526     if (r < 255 || g < 255 || b < 255) {
   527         texture->modMode |= SDL_TEXTUREMODULATE_COLOR;
   528     } else {
   529         texture->modMode &= ~SDL_TEXTUREMODULATE_COLOR;
   530     }
   531     texture->r = r;
   532     texture->g = g;
   533     texture->b = b;
   534     if (renderer->SetTextureColorMod) {
   535         return renderer->SetTextureColorMod(renderer, texture);
   536     } else {
   537         return 0;
   538     }
   539 }
   540 
   541 int
   542 SDL_GetTextureColorMod(SDL_Texture * texture, Uint8 * r, Uint8 * g,
   543                        Uint8 * b)
   544 {
   545     SDL_Renderer *renderer;
   546 
   547     CHECK_TEXTURE_MAGIC(texture, -1);
   548 
   549     renderer = texture->renderer;
   550     if (r) {
   551         *r = texture->r;
   552     }
   553     if (g) {
   554         *g = texture->g;
   555     }
   556     if (b) {
   557         *b = texture->b;
   558     }
   559     return 0;
   560 }
   561 
   562 int
   563 SDL_SetTextureAlphaMod(SDL_Texture * texture, Uint8 alpha)
   564 {
   565     SDL_Renderer *renderer;
   566 
   567     CHECK_TEXTURE_MAGIC(texture, -1);
   568 
   569     renderer = texture->renderer;
   570     if (alpha < 255) {
   571         texture->modMode |= SDL_TEXTUREMODULATE_ALPHA;
   572     } else {
   573         texture->modMode &= ~SDL_TEXTUREMODULATE_ALPHA;
   574     }
   575     texture->a = alpha;
   576     if (renderer->SetTextureAlphaMod) {
   577         return renderer->SetTextureAlphaMod(renderer, texture);
   578     } else {
   579         return 0;
   580     }
   581 }
   582 
   583 int
   584 SDL_GetTextureAlphaMod(SDL_Texture * texture, Uint8 * alpha)
   585 {
   586     CHECK_TEXTURE_MAGIC(texture, -1);
   587 
   588     if (alpha) {
   589         *alpha = texture->a;
   590     }
   591     return 0;
   592 }
   593 
   594 int
   595 SDL_SetTextureBlendMode(SDL_Texture * texture, SDL_BlendMode blendMode)
   596 {
   597     SDL_Renderer *renderer;
   598 
   599     CHECK_TEXTURE_MAGIC(texture, -1);
   600 
   601     renderer = texture->renderer;
   602     texture->blendMode = blendMode;
   603     if (renderer->SetTextureBlendMode) {
   604         return renderer->SetTextureBlendMode(renderer, texture);
   605     } else {
   606         return 0;
   607     }
   608 }
   609 
   610 int
   611 SDL_GetTextureBlendMode(SDL_Texture * texture, SDL_BlendMode *blendMode)
   612 {
   613     CHECK_TEXTURE_MAGIC(texture, -1);
   614 
   615     if (blendMode) {
   616         *blendMode = texture->blendMode;
   617     }
   618     return 0;
   619 }
   620 
   621 int
   622 SDL_UpdateTexture(SDL_Texture * texture, const SDL_Rect * rect,
   623                   const void *pixels, int pitch)
   624 {
   625     SDL_Renderer *renderer;
   626     SDL_Rect full_rect;
   627 
   628     CHECK_TEXTURE_MAGIC(texture, -1);
   629 
   630     renderer = texture->renderer;
   631     if (!renderer->UpdateTexture) {
   632         SDL_Unsupported();
   633         return -1;
   634     }
   635     if (!rect) {
   636         full_rect.x = 0;
   637         full_rect.y = 0;
   638         full_rect.w = texture->w;
   639         full_rect.h = texture->h;
   640         rect = &full_rect;
   641     }
   642     return renderer->UpdateTexture(renderer, texture, rect, pixels, pitch);
   643 }
   644 
   645 int
   646 SDL_LockTexture(SDL_Texture * texture, const SDL_Rect * rect, int markDirty,
   647                 void **pixels, int *pitch)
   648 {
   649     SDL_Renderer *renderer;
   650     SDL_Rect full_rect;
   651 
   652     CHECK_TEXTURE_MAGIC(texture, -1);
   653 
   654     if (texture->access != SDL_TEXTUREACCESS_STREAMING) {
   655         SDL_SetError("SDL_LockTexture(): texture must be streaming");
   656         return -1;
   657     }
   658     renderer = texture->renderer;
   659     if (!renderer->LockTexture) {
   660         SDL_Unsupported();
   661         return -1;
   662     }
   663     if (!rect) {
   664         full_rect.x = 0;
   665         full_rect.y = 0;
   666         full_rect.w = texture->w;
   667         full_rect.h = texture->h;
   668         rect = &full_rect;
   669     }
   670     return renderer->LockTexture(renderer, texture, rect, markDirty, pixels,
   671                                  pitch);
   672 }
   673 
   674 void
   675 SDL_UnlockTexture(SDL_Texture * texture)
   676 {
   677     SDL_Renderer *renderer;
   678 
   679     CHECK_TEXTURE_MAGIC(texture, );
   680 
   681     if (texture->access != SDL_TEXTUREACCESS_STREAMING) {
   682         return;
   683     }
   684     renderer = texture->renderer;
   685     if (!renderer->UnlockTexture) {
   686         return;
   687     }
   688     renderer->UnlockTexture(renderer, texture);
   689 }
   690 
   691 void
   692 SDL_DirtyTexture(SDL_Texture * texture, int numrects,
   693                  const SDL_Rect * rects)
   694 {
   695     SDL_Renderer *renderer;
   696 
   697     CHECK_TEXTURE_MAGIC(texture, );
   698 
   699     if (texture->access != SDL_TEXTUREACCESS_STREAMING) {
   700         return;
   701     }
   702     renderer = texture->renderer;
   703     if (!renderer->DirtyTexture) {
   704         return;
   705     }
   706     renderer->DirtyTexture(renderer, texture, numrects, rects);
   707 }
   708 
   709 int
   710 SDL_SetRenderDrawColor(SDL_Renderer * renderer,
   711                        Uint8 r, Uint8 g, Uint8 b, Uint8 a)
   712 {
   713     CHECK_RENDERER_MAGIC(renderer, -1);
   714 
   715     renderer->r = r;
   716     renderer->g = g;
   717     renderer->b = b;
   718     renderer->a = a;
   719     return 0;
   720 }
   721 
   722 int
   723 SDL_GetRenderDrawColor(SDL_Renderer * renderer,
   724                        Uint8 * r, Uint8 * g, Uint8 * b, Uint8 * a)
   725 {
   726     CHECK_RENDERER_MAGIC(renderer, -1);
   727 
   728     if (r) {
   729         *r = renderer->r;
   730     }
   731     if (g) {
   732         *g = renderer->g;
   733     }
   734     if (b) {
   735         *b = renderer->b;
   736     }
   737     if (a) {
   738         *a = renderer->a;
   739     }
   740     return 0;
   741 }
   742 
   743 int
   744 SDL_SetRenderDrawBlendMode(SDL_Renderer * renderer, SDL_BlendMode blendMode)
   745 {
   746     CHECK_RENDERER_MAGIC(renderer, -1);
   747 
   748     renderer->blendMode = blendMode;
   749     return 0;
   750 }
   751 
   752 int
   753 SDL_GetRenderDrawBlendMode(SDL_Renderer * renderer, SDL_BlendMode *blendMode)
   754 {
   755     CHECK_RENDERER_MAGIC(renderer, -1);
   756 
   757     *blendMode = renderer->blendMode;
   758     return 0;
   759 }
   760 
   761 int
   762 SDL_RenderClear(SDL_Renderer * renderer)
   763 {
   764     CHECK_RENDERER_MAGIC(renderer, -1);
   765 
   766     if (!renderer->RenderClear) {
   767         SDL_BlendMode blendMode = renderer->blendMode;
   768         int status;
   769 
   770         if (blendMode >= SDL_BLENDMODE_BLEND) {
   771             SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_NONE);
   772         }
   773 
   774         status = SDL_RenderFillRect(renderer, NULL);
   775 
   776         if (blendMode >= SDL_BLENDMODE_BLEND) {
   777             SDL_SetRenderDrawBlendMode(renderer, blendMode);
   778         }
   779         return status;
   780     }
   781     return renderer->RenderClear(renderer);
   782 }
   783 
   784 int
   785 SDL_RenderDrawPoint(SDL_Renderer * renderer, int x, int y)
   786 {
   787     SDL_Point point;
   788 
   789     point.x = x;
   790     point.y = y;
   791     return SDL_RenderDrawPoints(renderer, &point, 1);
   792 }
   793 
   794 int
   795 SDL_RenderDrawPoints(SDL_Renderer * renderer,
   796                      const SDL_Point * points, int count)
   797 {
   798     CHECK_RENDERER_MAGIC(renderer, -1);
   799 
   800     if (!points) {
   801         SDL_SetError("SDL_RenderDrawPoints(): Passed NULL points");
   802         return -1;
   803     }
   804     if (count < 1) {
   805         return 0;
   806     }
   807     return renderer->RenderDrawPoints(renderer, points, count);
   808 }
   809 
   810 int
   811 SDL_RenderDrawLine(SDL_Renderer * renderer, int x1, int y1, int x2, int y2)
   812 {
   813     SDL_Point points[2];
   814 
   815     points[0].x = x1;
   816     points[0].y = y1;
   817     points[1].x = x2;
   818     points[1].y = y2;
   819     return SDL_RenderDrawLines(renderer, points, 2);
   820 }
   821 
   822 int
   823 SDL_RenderDrawLines(SDL_Renderer * renderer,
   824                     const SDL_Point * points, int count)
   825 {
   826     CHECK_RENDERER_MAGIC(renderer, -1);
   827 
   828     if (!points) {
   829         SDL_SetError("SDL_RenderDrawLines(): Passed NULL points");
   830         return -1;
   831     }
   832     if (count < 2) {
   833         return 0;
   834     }
   835     return renderer->RenderDrawLines(renderer, points, count);
   836 }
   837 
   838 int
   839 SDL_RenderDrawRect(SDL_Renderer * renderer, const SDL_Rect * rect)
   840 {
   841     SDL_Rect full_rect;
   842     SDL_Point points[5];
   843 
   844     CHECK_RENDERER_MAGIC(renderer, -1);
   845 
   846     /* If 'rect' == NULL, then outline the whole surface */
   847     if (!rect) {
   848         SDL_Window *window = renderer->window;
   849 
   850         full_rect.x = 0;
   851         full_rect.y = 0;
   852         SDL_GetWindowSize(window, &full_rect.w, &full_rect.h);
   853         rect = &full_rect;
   854     }
   855 
   856     points[0].x = rect->x;
   857     points[0].y = rect->y;
   858     points[1].x = rect->x+rect->w-1;
   859     points[1].y = rect->y;
   860     points[2].x = rect->x+rect->w-1;
   861     points[2].y = rect->y+rect->h-1;
   862     points[3].x = rect->x;
   863     points[3].y = rect->y+rect->h-1;
   864     points[4].x = rect->x;
   865     points[4].y = rect->y;
   866     return SDL_RenderDrawLines(renderer, points, 5);
   867 }
   868 
   869 int
   870 SDL_RenderDrawRects(SDL_Renderer * renderer,
   871                     const SDL_Rect ** rects, int count)
   872 {
   873     int i;
   874 
   875     CHECK_RENDERER_MAGIC(renderer, -1);
   876 
   877     if (!rects) {
   878         SDL_SetError("SDL_RenderDrawRects(): Passed NULL rects");
   879         return -1;
   880     }
   881     if (count < 1) {
   882         return 0;
   883     }
   884 
   885     /* Check for NULL rect, which means fill entire window */
   886     for (i = 0; i < count; ++i) {
   887         if (SDL_RenderDrawRect(renderer, rects[i]) < 0) {
   888             return -1;
   889         }
   890     }
   891     return 0;
   892 }
   893 
   894 int
   895 SDL_RenderFillRect(SDL_Renderer * renderer, const SDL_Rect * rect)
   896 {
   897     return SDL_RenderFillRects(renderer, &rect, 1);
   898 }
   899 
   900 int
   901 SDL_RenderFillRects(SDL_Renderer * renderer,
   902                     const SDL_Rect ** rects, int count)
   903 {
   904     int i;
   905 
   906     CHECK_RENDERER_MAGIC(renderer, -1);
   907 
   908     if (!rects) {
   909         SDL_SetError("SDL_RenderFillRects(): Passed NULL rects");
   910         return -1;
   911     }
   912     if (count < 1) {
   913         return 0;
   914     }
   915 
   916     /* Check for NULL rect, which means fill entire window */
   917     for (i = 0; i < count; ++i) {
   918         if (rects[i] == NULL) {
   919             SDL_Window *window = renderer->window;
   920             SDL_Rect full_rect;
   921             const SDL_Rect *rect;
   922 
   923             full_rect.x = 0;
   924             full_rect.y = 0;
   925             SDL_GetWindowSize(window, &full_rect.w, &full_rect.h);
   926             rect = &full_rect;
   927             return renderer->RenderFillRects(renderer, &rect, 1);
   928         }
   929     }
   930     return renderer->RenderFillRects(renderer, rects, count);
   931 }
   932 
   933 int
   934 SDL_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
   935                const SDL_Rect * srcrect, const SDL_Rect * dstrect)
   936 {
   937     SDL_Window *window;
   938     SDL_Rect real_srcrect;
   939     SDL_Rect real_dstrect;
   940 
   941     CHECK_RENDERER_MAGIC(renderer, -1);
   942     CHECK_TEXTURE_MAGIC(texture, -1);
   943 
   944     if (renderer != texture->renderer) {
   945         SDL_SetError("Texture was not created with this renderer");
   946         return -1;
   947     }
   948     window = renderer->window;
   949 
   950     real_srcrect.x = 0;
   951     real_srcrect.y = 0;
   952     real_srcrect.w = texture->w;
   953     real_srcrect.h = texture->h;
   954     if (srcrect) {
   955         if (!SDL_IntersectRect(srcrect, &real_srcrect, &real_srcrect)) {
   956             return 0;
   957         }
   958     }
   959 
   960     real_dstrect.x = 0;
   961     real_dstrect.y = 0;
   962     SDL_GetWindowSize(window, &real_dstrect.w, &real_dstrect.h);
   963     if (dstrect) {
   964         if (!SDL_IntersectRect(dstrect, &real_dstrect, &real_dstrect)) {
   965             return 0;
   966         }
   967         /* Clip srcrect by the same amount as dstrect was clipped */
   968         if (dstrect->w != real_dstrect.w) {
   969             int deltax = (real_dstrect.x - dstrect->x);
   970             int deltaw = (real_dstrect.w - dstrect->w);
   971             real_srcrect.x += (deltax * real_srcrect.w) / dstrect->w;
   972             real_srcrect.w += (deltaw * real_srcrect.w) / dstrect->w;
   973         }
   974         if (dstrect->h != real_dstrect.h) {
   975             int deltay = (real_dstrect.y - dstrect->y);
   976             int deltah = (real_dstrect.h - dstrect->h);
   977             real_srcrect.y += (deltay * real_srcrect.h) / dstrect->h;
   978             real_srcrect.h += (deltah * real_srcrect.h) / dstrect->h;
   979         }
   980     }
   981 
   982     return renderer->RenderCopy(renderer, texture, &real_srcrect,
   983                                 &real_dstrect);
   984 }
   985 
   986 int
   987 SDL_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
   988                      Uint32 format, void * pixels, int pitch)
   989 {
   990     SDL_Window *window;
   991     SDL_Rect real_rect;
   992 
   993     CHECK_RENDERER_MAGIC(renderer, -1);
   994 
   995     if (!renderer->RenderReadPixels) {
   996         SDL_Unsupported();
   997         return -1;
   998     }
   999     window = renderer->window;
  1000 
  1001     if (!format) {
  1002         format = SDL_GetWindowPixelFormat(window);
  1003     }
  1004 
  1005     real_rect.x = 0;
  1006     real_rect.y = 0;
  1007     SDL_GetWindowSize(window, &real_rect.w, &real_rect.h);
  1008     if (rect) {
  1009         if (!SDL_IntersectRect(rect, &real_rect, &real_rect)) {
  1010             return 0;
  1011         }
  1012         if (real_rect.y > rect->y) {
  1013             pixels = (Uint8 *)pixels + pitch * (real_rect.y - rect->y);
  1014         }
  1015         if (real_rect.x > rect->x) {
  1016             int bpp = SDL_BYTESPERPIXEL(SDL_GetWindowPixelFormat(window));
  1017             pixels = (Uint8 *)pixels + bpp * (real_rect.x - rect->x);
  1018         }
  1019     }
  1020 
  1021     return renderer->RenderReadPixels(renderer, &real_rect,
  1022                                       format, pixels, pitch);
  1023 }
  1024 
  1025 int
  1026 SDL_RenderWritePixels(SDL_Renderer * renderer, const SDL_Rect * rect,
  1027                       Uint32 format, const void * pixels, int pitch)
  1028 {
  1029     SDL_Window *window;
  1030     SDL_Rect real_rect;
  1031 
  1032     CHECK_RENDERER_MAGIC(renderer, -1);
  1033 
  1034     if (!renderer->RenderWritePixels) {
  1035         SDL_Unsupported();
  1036         return -1;
  1037     }
  1038     window = renderer->window;
  1039 
  1040     if (!format) {
  1041         format = SDL_GetWindowPixelFormat(window);
  1042     }
  1043 
  1044     real_rect.x = 0;
  1045     real_rect.y = 0;
  1046     SDL_GetWindowSize(window, &real_rect.w, &real_rect.h);
  1047     if (rect) {
  1048         if (!SDL_IntersectRect(rect, &real_rect, &real_rect)) {
  1049             return 0;
  1050         }
  1051         if (real_rect.y > rect->y) {
  1052             pixels = (const Uint8 *)pixels + pitch * (real_rect.y - rect->y);
  1053         }
  1054         if (real_rect.x > rect->x) {
  1055             int bpp = SDL_BYTESPERPIXEL(SDL_GetWindowPixelFormat(window));
  1056             pixels = (const Uint8 *)pixels + bpp * (real_rect.x - rect->x);
  1057         }
  1058     }
  1059 
  1060     return renderer->RenderWritePixels(renderer, &real_rect,
  1061                                        format, pixels, pitch);
  1062 }
  1063 
  1064 void
  1065 SDL_RenderPresent(SDL_Renderer * renderer)
  1066 {
  1067     CHECK_RENDERER_MAGIC(renderer, );
  1068 
  1069     renderer->RenderPresent(renderer);
  1070 }
  1071 
  1072 void
  1073 SDL_DestroyTexture(SDL_Texture * texture)
  1074 {
  1075     SDL_Renderer *renderer;
  1076 
  1077     CHECK_TEXTURE_MAGIC(texture, );
  1078     texture->magic = NULL;
  1079 
  1080     renderer = texture->renderer;
  1081     if (texture->next) {
  1082         texture->next->prev = texture->prev;
  1083     }
  1084     if (texture->prev) {
  1085         texture->prev->next = texture->next;
  1086     } else {
  1087         renderer->textures = texture->next;
  1088     }
  1089 
  1090     renderer->DestroyTexture(renderer, texture);
  1091     SDL_free(texture);
  1092 }
  1093 
  1094 void
  1095 SDL_DestroyRenderer(SDL_Renderer * renderer)
  1096 {
  1097     CHECK_RENDERER_MAGIC(renderer, );
  1098 
  1099     SDL_DelEventWatch(SDL_RendererEventWatch, renderer);
  1100 
  1101     /* Free existing textures for this renderer */
  1102     while (renderer->textures) {
  1103         SDL_DestroyTexture(renderer->textures);
  1104     }
  1105 
  1106     /* It's no longer magical... */
  1107     renderer->magic = NULL;
  1108 
  1109     /* Free the renderer instance */
  1110     renderer->DestroyRenderer(renderer);
  1111 }
  1112 
  1113 /* vi: set ts=4 sw=4 expandtab: */