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