src/render/SDL_render.c
author Sam Lantinga <slouken@libsdl.org>
Sat, 05 Feb 2011 16:07:10 -0800
changeset 5199 164f20ba08eb
parent 5195 bb45ecd958d8
child 5201 523409574510
permissions -rw-r--r--
Updated the DirectFB support, from Couriersud

attached is a working directfb driver diff which works with the current
changes. There are a number of changes around it as well, e.g.
configure.in.

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