src/render/SDL_render.c
author Sam Lantinga <slouken@libsdl.org>
Thu, 03 Feb 2011 00:54:29 -0800
changeset 5158 b3ccd1947786
parent 5157 657543cc92f9
child 5166 4d39eeaad00b
permissions -rw-r--r--
Simplified and improved the process of creating a texture from a surface.
     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 static SDL_bool
   156 IsSupportedFormat(SDL_Renderer * renderer, Uint32 format)
   157 {
   158     Uint32 i;
   159 
   160     for (i = 0; i < renderer->info.num_texture_formats; ++i) {
   161         if (renderer->info.texture_formats[i] == format) {
   162             return SDL_TRUE;
   163         }
   164     }
   165     return SDL_FALSE;
   166 }
   167 
   168 static Uint32
   169 GetClosestSupportedFormat(SDL_Renderer * renderer, Uint32 format)
   170 {
   171     Uint32 i;
   172     SDL_bool hasAlpha = SDL_ISPIXELFORMAT_ALPHA(format);
   173 
   174     /* We just want to match the first format that has the same channels */
   175     for (i = 0; i < renderer->info.num_texture_formats; ++i) {
   176         if (SDL_ISPIXELFORMAT_ALPHA(renderer->info.texture_formats[i]) == hasAlpha) {
   177             return renderer->info.texture_formats[i];
   178         }
   179     }
   180     return renderer->info.texture_formats[0];
   181 }
   182 
   183 SDL_Texture *
   184 SDL_CreateTexture(SDL_Renderer * renderer, Uint32 format, int access, int w, int h)
   185 {
   186     SDL_Texture *texture;
   187 
   188     CHECK_RENDERER_MAGIC(renderer, NULL);
   189 
   190     if (SDL_ISPIXELFORMAT_INDEXED(format)) {
   191         SDL_SetError("Palettized textures are not supported");
   192         return NULL;
   193     }
   194     if (w <= 0 || h <= 0) {
   195         SDL_SetError("Texture dimensions can't be 0");
   196         return NULL;
   197     }
   198     texture = (SDL_Texture *) SDL_calloc(1, sizeof(*texture));
   199     if (!texture) {
   200         SDL_OutOfMemory();
   201         return NULL;
   202     }
   203     texture->magic = &texture_magic;
   204     texture->format = format;
   205     texture->access = access;
   206     texture->w = w;
   207     texture->h = h;
   208     texture->r = 255;
   209     texture->g = 255;
   210     texture->b = 255;
   211     texture->a = 255;
   212     texture->renderer = renderer;
   213     texture->next = renderer->textures;
   214     if (renderer->textures) {
   215         renderer->textures->prev = texture;
   216     }
   217     renderer->textures = texture;
   218 
   219     if (IsSupportedFormat(renderer, format)) {
   220         if (renderer->CreateTexture(renderer, texture) < 0) {
   221             SDL_DestroyTexture(texture);
   222             return 0;
   223         }
   224     } else {
   225         texture->native = SDL_CreateTexture(renderer,
   226                                 GetClosestSupportedFormat(renderer, format),
   227                                 access, w, h);
   228         if (!texture->native) {
   229             SDL_DestroyTexture(texture);
   230             return NULL;
   231         }
   232 
   233         if (SDL_ISPIXELFORMAT_FOURCC(texture->format)) {
   234             texture->yuv = SDL_SW_CreateYUVTexture(format, w, h);
   235             if (!texture->yuv) {
   236                 SDL_DestroyTexture(texture);
   237                 return NULL;
   238             }
   239         } else if (access == SDL_TEXTUREACCESS_STREAMING) {
   240             /* The pitch is 4 byte aligned */
   241             texture->pitch = (((w * SDL_BYTESPERPIXEL(format)) + 3) & ~3);
   242             texture->pixels = SDL_malloc(texture->pitch * h);
   243             if (!texture->pixels) {
   244                 SDL_DestroyTexture(texture);
   245                 return NULL;
   246             }
   247         }
   248     }
   249     return texture;
   250 }
   251 
   252 SDL_Texture *
   253 SDL_CreateTextureFromSurface(SDL_Renderer * renderer, SDL_Surface * surface)
   254 {
   255     const SDL_PixelFormat *fmt;
   256     SDL_bool needAlpha;
   257     Uint32 i;
   258     Uint32 format;
   259     int bpp;
   260     Uint32 Rmask, Gmask, Bmask, Amask;
   261     SDL_Texture *texture;
   262 
   263     CHECK_RENDERER_MAGIC(renderer, NULL);
   264 
   265     if (!surface) {
   266         SDL_SetError("SDL_CreateTextureFromSurface() passed NULL surface");
   267         return NULL;
   268     }
   269 
   270     /* See what the best texture format is */
   271     fmt = surface->format;
   272     if (fmt->Amask || SDL_GetColorKey(surface, NULL) == 0) {
   273         needAlpha = SDL_TRUE;
   274     } else {
   275         needAlpha = SDL_FALSE;
   276     }
   277     format = renderer->info.texture_formats[0];
   278     for (i = 0; i < renderer->info.num_texture_formats; ++i) {
   279         if (SDL_ISPIXELFORMAT_ALPHA(renderer->info.texture_formats[i]) == needAlpha) {
   280             format = renderer->info.texture_formats[i];
   281             break;
   282         }
   283     }
   284 
   285     if (!SDL_PixelFormatEnumToMasks(format, &bpp,
   286                                     &Rmask, &Gmask, &Bmask, &Amask)) {
   287         SDL_SetError("Unknown pixel format");
   288         return NULL;
   289     }
   290 
   291     texture = SDL_CreateTexture(renderer, format, SDL_TEXTUREACCESS_STATIC,
   292                                 surface->w, surface->h);
   293     if (!texture) {
   294         return NULL;
   295     }
   296 
   297     if (bpp == fmt->BitsPerPixel && Rmask == fmt->Rmask && Gmask == fmt->Gmask
   298         && Bmask == fmt->Bmask && Amask == fmt->Amask) {
   299         if (SDL_MUSTLOCK(surface)) {
   300             SDL_LockSurface(surface);
   301             SDL_UpdateTexture(texture, NULL, surface->pixels, surface->pitch);
   302             SDL_UnlockSurface(surface);
   303         } else {
   304             SDL_UpdateTexture(texture, NULL, surface->pixels, surface->pitch);
   305         }
   306     } else {
   307         SDL_PixelFormat dst_fmt;
   308         SDL_Surface *temp = NULL;
   309 
   310         /* Set up a destination surface for the texture update */
   311         SDL_InitFormat(&dst_fmt, bpp, Rmask, Gmask, Bmask, Amask);
   312         temp = SDL_ConvertSurface(surface, &dst_fmt, 0);
   313         if (temp) {
   314             SDL_UpdateTexture(texture, NULL, temp->pixels, temp->pitch);
   315             SDL_FreeSurface(temp);
   316         } else {
   317             SDL_DestroyTexture(texture);
   318             return NULL;
   319         }
   320     }
   321 
   322     {
   323         Uint8 r, g, b, a;
   324         SDL_BlendMode blendMode;
   325 
   326         SDL_GetSurfaceColorMod(surface, &r, &g, &b);
   327         SDL_SetTextureColorMod(texture, r, g, b);
   328 
   329         SDL_GetSurfaceAlphaMod(surface, &a);
   330         SDL_SetTextureAlphaMod(texture, a);
   331 
   332         if (SDL_GetColorKey(surface, NULL) == 0) {
   333             /* We converted to a texture with alpha format */
   334             SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_BLEND);
   335         } else {
   336             SDL_GetSurfaceBlendMode(surface, &blendMode);
   337             SDL_SetTextureBlendMode(texture, blendMode);
   338         }
   339     }
   340     return texture;
   341 }
   342 
   343 int
   344 SDL_QueryTexture(SDL_Texture * texture, Uint32 * format, int *access,
   345                  int *w, int *h)
   346 {
   347     CHECK_TEXTURE_MAGIC(texture, -1);
   348 
   349     if (format) {
   350         *format = texture->format;
   351     }
   352     if (access) {
   353         *access = texture->access;
   354     }
   355     if (w) {
   356         *w = texture->w;
   357     }
   358     if (h) {
   359         *h = texture->h;
   360     }
   361     return 0;
   362 }
   363 
   364 int
   365 SDL_SetTextureColorMod(SDL_Texture * texture, Uint8 r, Uint8 g, Uint8 b)
   366 {
   367     SDL_Renderer *renderer;
   368 
   369     CHECK_TEXTURE_MAGIC(texture, -1);
   370 
   371     renderer = texture->renderer;
   372     if (r < 255 || g < 255 || b < 255) {
   373         texture->modMode |= SDL_TEXTUREMODULATE_COLOR;
   374     } else {
   375         texture->modMode &= ~SDL_TEXTUREMODULATE_COLOR;
   376     }
   377     texture->r = r;
   378     texture->g = g;
   379     texture->b = b;
   380     if (texture->native) {
   381         return SDL_SetTextureColorMod(texture->native, r, g, b);
   382     } else if (renderer->SetTextureColorMod) {
   383         return renderer->SetTextureColorMod(renderer, texture);
   384     } else {
   385         return 0;
   386     }
   387 }
   388 
   389 int
   390 SDL_GetTextureColorMod(SDL_Texture * texture, Uint8 * r, Uint8 * g,
   391                        Uint8 * b)
   392 {
   393     SDL_Renderer *renderer;
   394 
   395     CHECK_TEXTURE_MAGIC(texture, -1);
   396 
   397     renderer = texture->renderer;
   398     if (r) {
   399         *r = texture->r;
   400     }
   401     if (g) {
   402         *g = texture->g;
   403     }
   404     if (b) {
   405         *b = texture->b;
   406     }
   407     return 0;
   408 }
   409 
   410 int
   411 SDL_SetTextureAlphaMod(SDL_Texture * texture, Uint8 alpha)
   412 {
   413     SDL_Renderer *renderer;
   414 
   415     CHECK_TEXTURE_MAGIC(texture, -1);
   416 
   417     renderer = texture->renderer;
   418     if (alpha < 255) {
   419         texture->modMode |= SDL_TEXTUREMODULATE_ALPHA;
   420     } else {
   421         texture->modMode &= ~SDL_TEXTUREMODULATE_ALPHA;
   422     }
   423     texture->a = alpha;
   424     if (texture->native) {
   425         return SDL_SetTextureAlphaMod(texture->native, alpha);
   426     } else if (renderer->SetTextureAlphaMod) {
   427         return renderer->SetTextureAlphaMod(renderer, texture);
   428     } else {
   429         return 0;
   430     }
   431 }
   432 
   433 int
   434 SDL_GetTextureAlphaMod(SDL_Texture * texture, Uint8 * alpha)
   435 {
   436     CHECK_TEXTURE_MAGIC(texture, -1);
   437 
   438     if (alpha) {
   439         *alpha = texture->a;
   440     }
   441     return 0;
   442 }
   443 
   444 int
   445 SDL_SetTextureBlendMode(SDL_Texture * texture, SDL_BlendMode blendMode)
   446 {
   447     SDL_Renderer *renderer;
   448 
   449     CHECK_TEXTURE_MAGIC(texture, -1);
   450 
   451     renderer = texture->renderer;
   452     texture->blendMode = blendMode;
   453     if (texture->native) {
   454         return SDL_SetTextureBlendMode(texture, blendMode);
   455     } else if (renderer->SetTextureBlendMode) {
   456         return renderer->SetTextureBlendMode(renderer, texture);
   457     } else {
   458         return 0;
   459     }
   460 }
   461 
   462 int
   463 SDL_GetTextureBlendMode(SDL_Texture * texture, SDL_BlendMode *blendMode)
   464 {
   465     CHECK_TEXTURE_MAGIC(texture, -1);
   466 
   467     if (blendMode) {
   468         *blendMode = texture->blendMode;
   469     }
   470     return 0;
   471 }
   472 
   473 static int
   474 SDL_UpdateTextureYUV(SDL_Texture * texture, const SDL_Rect * rect,
   475                      const void *pixels, int pitch)
   476 {
   477     SDL_Texture *native = texture->native;
   478     SDL_Rect full_rect;
   479 
   480     if (SDL_SW_UpdateYUVTexture(texture->yuv, rect, pixels, pitch) < 0) {
   481         return -1;
   482     }
   483 
   484     full_rect.x = 0;
   485     full_rect.y = 0;
   486     full_rect.w = texture->w;
   487     full_rect.h = texture->h;
   488     rect = &full_rect;
   489 
   490     if (texture->access == SDL_TEXTUREACCESS_STREAMING) {
   491         /* We can lock the texture and copy to it */
   492         void *native_pixels;
   493         int native_pitch;
   494 
   495         if (SDL_LockTexture(native, rect, &native_pixels, &native_pitch) < 0) {
   496             return -1;
   497         }
   498         SDL_SW_CopyYUVToRGB(texture->yuv, rect, native->format,
   499                             rect->w, rect->h, native_pixels, native_pitch);
   500         SDL_UnlockTexture(native);
   501     } else {
   502         /* Use a temporary buffer for updating */
   503         void *temp_pixels;
   504         int temp_pitch;
   505 
   506         temp_pitch = (((rect->w * SDL_BYTESPERPIXEL(native->format)) + 3) & ~3);
   507         temp_pixels = SDL_malloc(rect->h * temp_pitch);
   508         if (!temp_pixels) {
   509             SDL_OutOfMemory();
   510             return -1;
   511         }
   512         SDL_SW_CopyYUVToRGB(texture->yuv, rect, native->format,
   513                             rect->w, rect->h, temp_pixels, temp_pitch);
   514         SDL_UpdateTexture(native, rect, temp_pixels, temp_pitch);
   515         SDL_free(temp_pixels);
   516     }
   517     return 0;
   518 }
   519 
   520 static int
   521 SDL_UpdateTextureNative(SDL_Texture * texture, const SDL_Rect * rect,
   522                         const void *pixels, int pitch)
   523 {
   524     SDL_Texture *native = texture->native;
   525 
   526     if (texture->access == SDL_TEXTUREACCESS_STREAMING) {
   527         /* We can lock the texture and copy to it */
   528         void *native_pixels;
   529         int native_pitch;
   530 
   531         if (SDL_LockTexture(native, rect, &native_pixels, &native_pitch) < 0) {
   532             return -1;
   533         }
   534         SDL_ConvertPixels(rect->w, rect->h,
   535                           texture->format, pixels, pitch,
   536                           native->format, native_pixels, native_pitch);
   537         SDL_UnlockTexture(native);
   538     } else {
   539         /* Use a temporary buffer for updating */
   540         void *temp_pixels;
   541         int temp_pitch;
   542 
   543         temp_pitch = (((rect->w * SDL_BYTESPERPIXEL(native->format)) + 3) & ~3);
   544         temp_pixels = SDL_malloc(rect->h * temp_pitch);
   545         if (!temp_pixels) {
   546             SDL_OutOfMemory();
   547             return -1;
   548         }
   549         SDL_ConvertPixels(rect->w, rect->h,
   550                           texture->format, pixels, pitch,
   551                           native->format, temp_pixels, temp_pitch);
   552         SDL_UpdateTexture(native, rect, temp_pixels, temp_pitch);
   553         SDL_free(temp_pixels);
   554     }
   555     return 0;
   556 }
   557 
   558 int
   559 SDL_UpdateTexture(SDL_Texture * texture, const SDL_Rect * rect,
   560                   const void *pixels, int pitch)
   561 {
   562     SDL_Renderer *renderer;
   563     SDL_Rect full_rect;
   564 
   565     CHECK_TEXTURE_MAGIC(texture, -1);
   566 
   567     if (!rect) {
   568         full_rect.x = 0;
   569         full_rect.y = 0;
   570         full_rect.w = texture->w;
   571         full_rect.h = texture->h;
   572         rect = &full_rect;
   573     }
   574 
   575     if (texture->yuv) {
   576         return SDL_UpdateTextureYUV(texture, rect, pixels, pitch);
   577     } else if (texture->native) {
   578         return SDL_UpdateTextureNative(texture, rect, pixels, pitch);
   579     } else {
   580         renderer = texture->renderer;
   581         return renderer->UpdateTexture(renderer, texture, rect, pixels, pitch);
   582     }
   583 }
   584 
   585 static int
   586 SDL_LockTextureYUV(SDL_Texture * texture, const SDL_Rect * rect,
   587                    void **pixels, int *pitch)
   588 {
   589     return SDL_SW_LockYUVTexture(texture->yuv, rect, pixels, pitch);
   590 }
   591 
   592 static int
   593 SDL_LockTextureNative(SDL_Texture * texture, const SDL_Rect * rect,
   594                       void **pixels, int *pitch)
   595 {
   596     texture->locked_rect = *rect;
   597     *pixels = (void *) ((Uint8 *) texture->pixels +
   598                         rect->y * texture->pitch +
   599                         rect->x * SDL_BYTESPERPIXEL(texture->format));
   600     *pitch = texture->pitch;
   601     return 0;
   602 }
   603 
   604 int
   605 SDL_LockTexture(SDL_Texture * texture, const SDL_Rect * rect,
   606                 void **pixels, int *pitch)
   607 {
   608     SDL_Renderer *renderer;
   609     SDL_Rect full_rect;
   610 
   611     CHECK_TEXTURE_MAGIC(texture, -1);
   612 
   613     if (texture->access != SDL_TEXTUREACCESS_STREAMING) {
   614         SDL_SetError("SDL_LockTexture(): texture must be streaming");
   615         return -1;
   616     }
   617 
   618     if (!rect) {
   619         full_rect.x = 0;
   620         full_rect.y = 0;
   621         full_rect.w = texture->w;
   622         full_rect.h = texture->h;
   623         rect = &full_rect;
   624     }
   625 
   626     if (texture->yuv) {
   627         return SDL_LockTextureYUV(texture, rect, pixels, pitch);
   628     } else if (texture->native) {
   629         return SDL_LockTextureNative(texture, rect, pixels, pitch);
   630     } else {
   631         renderer = texture->renderer;
   632         return renderer->LockTexture(renderer, texture, rect, pixels, pitch);
   633     }
   634 }
   635 
   636 static void
   637 SDL_UnlockTextureYUV(SDL_Texture * texture)
   638 {
   639     SDL_Texture *native = texture->native;
   640     void *native_pixels;
   641     int native_pitch;
   642     SDL_Rect rect;
   643 
   644     rect.x = 0;
   645     rect.y = 0;
   646     rect.w = texture->w;
   647     rect.h = texture->h;
   648 
   649     if (SDL_LockTexture(native, &rect, &native_pixels, &native_pitch) < 0) {
   650         return;
   651     }
   652     SDL_SW_CopyYUVToRGB(texture->yuv, &rect, native->format,
   653                         rect.w, rect.h, native_pixels, native_pitch);
   654     SDL_UnlockTexture(native);
   655 }
   656 
   657 void
   658 SDL_UnlockTextureNative(SDL_Texture * texture)
   659 {
   660     SDL_Texture *native = texture->native;
   661     void *native_pixels;
   662     int native_pitch;
   663     const SDL_Rect *rect = &texture->locked_rect;
   664     const void* pixels = (void *) ((Uint8 *) texture->pixels +
   665                         rect->y * texture->pitch +
   666                         rect->x * SDL_BYTESPERPIXEL(texture->format));
   667     int pitch = texture->pitch;
   668 
   669     if (SDL_LockTexture(native, rect, &native_pixels, &native_pitch) < 0) {
   670         return;
   671     }
   672     SDL_ConvertPixels(rect->w, rect->h,
   673                       texture->format, pixels, pitch,
   674                       native->format, native_pixels, native_pitch);
   675     SDL_UnlockTexture(native);
   676 }
   677 
   678 void
   679 SDL_UnlockTexture(SDL_Texture * texture)
   680 {
   681     SDL_Renderer *renderer;
   682 
   683     CHECK_TEXTURE_MAGIC(texture, );
   684 
   685     if (texture->access != SDL_TEXTUREACCESS_STREAMING) {
   686         return;
   687     }
   688     if (texture->yuv) {
   689         SDL_UnlockTextureYUV(texture);
   690     } else if (texture->native) {
   691         SDL_UnlockTextureNative(texture);
   692     } else {
   693         renderer = texture->renderer;
   694         renderer->UnlockTexture(renderer, texture);
   695     }
   696 }
   697 
   698 int
   699 SDL_SetRenderDrawColor(SDL_Renderer * renderer,
   700                        Uint8 r, Uint8 g, Uint8 b, Uint8 a)
   701 {
   702     CHECK_RENDERER_MAGIC(renderer, -1);
   703 
   704     renderer->r = r;
   705     renderer->g = g;
   706     renderer->b = b;
   707     renderer->a = a;
   708     return 0;
   709 }
   710 
   711 int
   712 SDL_GetRenderDrawColor(SDL_Renderer * renderer,
   713                        Uint8 * r, Uint8 * g, Uint8 * b, Uint8 * a)
   714 {
   715     CHECK_RENDERER_MAGIC(renderer, -1);
   716 
   717     if (r) {
   718         *r = renderer->r;
   719     }
   720     if (g) {
   721         *g = renderer->g;
   722     }
   723     if (b) {
   724         *b = renderer->b;
   725     }
   726     if (a) {
   727         *a = renderer->a;
   728     }
   729     return 0;
   730 }
   731 
   732 int
   733 SDL_SetRenderDrawBlendMode(SDL_Renderer * renderer, SDL_BlendMode blendMode)
   734 {
   735     CHECK_RENDERER_MAGIC(renderer, -1);
   736 
   737     renderer->blendMode = blendMode;
   738     return 0;
   739 }
   740 
   741 int
   742 SDL_GetRenderDrawBlendMode(SDL_Renderer * renderer, SDL_BlendMode *blendMode)
   743 {
   744     CHECK_RENDERER_MAGIC(renderer, -1);
   745 
   746     *blendMode = renderer->blendMode;
   747     return 0;
   748 }
   749 
   750 int
   751 SDL_RenderClear(SDL_Renderer * renderer)
   752 {
   753     CHECK_RENDERER_MAGIC(renderer, -1);
   754 
   755     if (!renderer->RenderClear) {
   756         SDL_BlendMode blendMode = renderer->blendMode;
   757         int status;
   758 
   759         if (blendMode >= SDL_BLENDMODE_BLEND) {
   760             SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_NONE);
   761         }
   762 
   763         status = SDL_RenderFillRect(renderer, NULL);
   764 
   765         if (blendMode >= SDL_BLENDMODE_BLEND) {
   766             SDL_SetRenderDrawBlendMode(renderer, blendMode);
   767         }
   768         return status;
   769     }
   770     return renderer->RenderClear(renderer);
   771 }
   772 
   773 int
   774 SDL_RenderDrawPoint(SDL_Renderer * renderer, int x, int y)
   775 {
   776     SDL_Point point;
   777 
   778     point.x = x;
   779     point.y = y;
   780     return SDL_RenderDrawPoints(renderer, &point, 1);
   781 }
   782 
   783 int
   784 SDL_RenderDrawPoints(SDL_Renderer * renderer,
   785                      const SDL_Point * points, int count)
   786 {
   787     CHECK_RENDERER_MAGIC(renderer, -1);
   788 
   789     if (!points) {
   790         SDL_SetError("SDL_RenderDrawPoints(): Passed NULL points");
   791         return -1;
   792     }
   793     if (count < 1) {
   794         return 0;
   795     }
   796     return renderer->RenderDrawPoints(renderer, points, count);
   797 }
   798 
   799 int
   800 SDL_RenderDrawLine(SDL_Renderer * renderer, int x1, int y1, int x2, int y2)
   801 {
   802     SDL_Point points[2];
   803 
   804     points[0].x = x1;
   805     points[0].y = y1;
   806     points[1].x = x2;
   807     points[1].y = y2;
   808     return SDL_RenderDrawLines(renderer, points, 2);
   809 }
   810 
   811 int
   812 SDL_RenderDrawLines(SDL_Renderer * renderer,
   813                     const SDL_Point * points, int count)
   814 {
   815     CHECK_RENDERER_MAGIC(renderer, -1);
   816 
   817     if (!points) {
   818         SDL_SetError("SDL_RenderDrawLines(): Passed NULL points");
   819         return -1;
   820     }
   821     if (count < 2) {
   822         return 0;
   823     }
   824     return renderer->RenderDrawLines(renderer, points, count);
   825 }
   826 
   827 int
   828 SDL_RenderDrawRect(SDL_Renderer * renderer, const SDL_Rect * rect)
   829 {
   830     SDL_Rect full_rect;
   831     SDL_Point points[5];
   832 
   833     CHECK_RENDERER_MAGIC(renderer, -1);
   834 
   835     /* If 'rect' == NULL, then outline the whole surface */
   836     if (!rect) {
   837         SDL_Window *window = renderer->window;
   838 
   839         full_rect.x = 0;
   840         full_rect.y = 0;
   841         SDL_GetWindowSize(window, &full_rect.w, &full_rect.h);
   842         rect = &full_rect;
   843     }
   844 
   845     points[0].x = rect->x;
   846     points[0].y = rect->y;
   847     points[1].x = rect->x+rect->w-1;
   848     points[1].y = rect->y;
   849     points[2].x = rect->x+rect->w-1;
   850     points[2].y = rect->y+rect->h-1;
   851     points[3].x = rect->x;
   852     points[3].y = rect->y+rect->h-1;
   853     points[4].x = rect->x;
   854     points[4].y = rect->y;
   855     return SDL_RenderDrawLines(renderer, points, 5);
   856 }
   857 
   858 int
   859 SDL_RenderDrawRects(SDL_Renderer * renderer,
   860                     const SDL_Rect ** rects, int count)
   861 {
   862     int i;
   863 
   864     CHECK_RENDERER_MAGIC(renderer, -1);
   865 
   866     if (!rects) {
   867         SDL_SetError("SDL_RenderDrawRects(): Passed NULL rects");
   868         return -1;
   869     }
   870     if (count < 1) {
   871         return 0;
   872     }
   873 
   874     /* Check for NULL rect, which means fill entire window */
   875     for (i = 0; i < count; ++i) {
   876         if (SDL_RenderDrawRect(renderer, rects[i]) < 0) {
   877             return -1;
   878         }
   879     }
   880     return 0;
   881 }
   882 
   883 int
   884 SDL_RenderFillRect(SDL_Renderer * renderer, const SDL_Rect * rect)
   885 {
   886     return SDL_RenderFillRects(renderer, &rect, 1);
   887 }
   888 
   889 int
   890 SDL_RenderFillRects(SDL_Renderer * renderer,
   891                     const SDL_Rect ** rects, int count)
   892 {
   893     int i;
   894 
   895     CHECK_RENDERER_MAGIC(renderer, -1);
   896 
   897     if (!rects) {
   898         SDL_SetError("SDL_RenderFillRects(): Passed NULL rects");
   899         return -1;
   900     }
   901     if (count < 1) {
   902         return 0;
   903     }
   904 
   905     /* Check for NULL rect, which means fill entire window */
   906     for (i = 0; i < count; ++i) {
   907         if (rects[i] == NULL) {
   908             SDL_Window *window = renderer->window;
   909             SDL_Rect full_rect;
   910             const SDL_Rect *rect;
   911 
   912             full_rect.x = 0;
   913             full_rect.y = 0;
   914             SDL_GetWindowSize(window, &full_rect.w, &full_rect.h);
   915             rect = &full_rect;
   916             return renderer->RenderFillRects(renderer, &rect, 1);
   917         }
   918     }
   919     return renderer->RenderFillRects(renderer, rects, count);
   920 }
   921 
   922 int
   923 SDL_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
   924                const SDL_Rect * srcrect, const SDL_Rect * dstrect)
   925 {
   926     SDL_Window *window;
   927     SDL_Rect real_srcrect;
   928     SDL_Rect real_dstrect;
   929 
   930     CHECK_RENDERER_MAGIC(renderer, -1);
   931     CHECK_TEXTURE_MAGIC(texture, -1);
   932 
   933     if (renderer != texture->renderer) {
   934         SDL_SetError("Texture was not created with this renderer");
   935         return -1;
   936     }
   937     window = renderer->window;
   938 
   939     real_srcrect.x = 0;
   940     real_srcrect.y = 0;
   941     real_srcrect.w = texture->w;
   942     real_srcrect.h = texture->h;
   943     if (srcrect) {
   944         if (!SDL_IntersectRect(srcrect, &real_srcrect, &real_srcrect)) {
   945             return 0;
   946         }
   947     }
   948 
   949     real_dstrect.x = 0;
   950     real_dstrect.y = 0;
   951     SDL_GetWindowSize(window, &real_dstrect.w, &real_dstrect.h);
   952     if (dstrect) {
   953         if (!SDL_IntersectRect(dstrect, &real_dstrect, &real_dstrect)) {
   954             return 0;
   955         }
   956         /* Clip srcrect by the same amount as dstrect was clipped */
   957         if (dstrect->w != real_dstrect.w) {
   958             int deltax = (real_dstrect.x - dstrect->x);
   959             int deltaw = (real_dstrect.w - dstrect->w);
   960             real_srcrect.x += (deltax * real_srcrect.w) / dstrect->w;
   961             real_srcrect.w += (deltaw * real_srcrect.w) / dstrect->w;
   962         }
   963         if (dstrect->h != real_dstrect.h) {
   964             int deltay = (real_dstrect.y - dstrect->y);
   965             int deltah = (real_dstrect.h - dstrect->h);
   966             real_srcrect.y += (deltay * real_srcrect.h) / dstrect->h;
   967             real_srcrect.h += (deltah * real_srcrect.h) / dstrect->h;
   968         }
   969     }
   970 
   971     if (texture->native) {
   972         texture = texture->native;
   973     }
   974 
   975     return renderer->RenderCopy(renderer, texture, &real_srcrect,
   976                                 &real_dstrect);
   977 }
   978 
   979 int
   980 SDL_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
   981                      Uint32 format, void * pixels, int pitch)
   982 {
   983     SDL_Window *window;
   984     SDL_Rect real_rect;
   985 
   986     CHECK_RENDERER_MAGIC(renderer, -1);
   987 
   988     if (!renderer->RenderReadPixels) {
   989         SDL_Unsupported();
   990         return -1;
   991     }
   992     window = renderer->window;
   993 
   994     if (!format) {
   995         format = SDL_GetWindowPixelFormat(window);
   996     }
   997 
   998     real_rect.x = 0;
   999     real_rect.y = 0;
  1000     SDL_GetWindowSize(window, &real_rect.w, &real_rect.h);
  1001     if (rect) {
  1002         if (!SDL_IntersectRect(rect, &real_rect, &real_rect)) {
  1003             return 0;
  1004         }
  1005         if (real_rect.y > rect->y) {
  1006             pixels = (Uint8 *)pixels + pitch * (real_rect.y - rect->y);
  1007         }
  1008         if (real_rect.x > rect->x) {
  1009             int bpp = SDL_BYTESPERPIXEL(SDL_GetWindowPixelFormat(window));
  1010             pixels = (Uint8 *)pixels + bpp * (real_rect.x - rect->x);
  1011         }
  1012     }
  1013 
  1014     return renderer->RenderReadPixels(renderer, &real_rect,
  1015                                       format, pixels, pitch);
  1016 }
  1017 
  1018 void
  1019 SDL_RenderPresent(SDL_Renderer * renderer)
  1020 {
  1021     CHECK_RENDERER_MAGIC(renderer, );
  1022 
  1023     renderer->RenderPresent(renderer);
  1024 }
  1025 
  1026 void
  1027 SDL_DestroyTexture(SDL_Texture * texture)
  1028 {
  1029     SDL_Renderer *renderer;
  1030 
  1031     CHECK_TEXTURE_MAGIC(texture, );
  1032     texture->magic = NULL;
  1033 
  1034     renderer = texture->renderer;
  1035     if (texture->next) {
  1036         texture->next->prev = texture->prev;
  1037     }
  1038     if (texture->prev) {
  1039         texture->prev->next = texture->next;
  1040     } else {
  1041         renderer->textures = texture->next;
  1042     }
  1043 
  1044     if (texture->native) {
  1045         SDL_DestroyTexture(texture->native);
  1046     }
  1047     if (texture->yuv) {
  1048         SDL_SW_DestroyYUVTexture(texture->yuv);
  1049     }
  1050     if (texture->pixels) {
  1051         SDL_free(texture->pixels);
  1052     }
  1053 
  1054     renderer->DestroyTexture(renderer, texture);
  1055     SDL_free(texture);
  1056 }
  1057 
  1058 void
  1059 SDL_DestroyRenderer(SDL_Renderer * renderer)
  1060 {
  1061     CHECK_RENDERER_MAGIC(renderer, );
  1062 
  1063     SDL_DelEventWatch(SDL_RendererEventWatch, renderer);
  1064 
  1065     /* Free existing textures for this renderer */
  1066     while (renderer->textures) {
  1067         SDL_DestroyTexture(renderer->textures);
  1068     }
  1069 
  1070     /* It's no longer magical... */
  1071     renderer->magic = NULL;
  1072 
  1073     /* Free the renderer instance */
  1074     renderer->DestroyRenderer(renderer);
  1075 }
  1076 
  1077 /* vi: set ts=4 sw=4 expandtab: */