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