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