src/render/software/SDL_render_sw.c
author Gabriel Jacobo <gabomdq@gmail.com>
Fri, 01 Jun 2012 19:51:08 -0300
changeset 6320 6077a1310907
parent 6283 03a7ceb3487b
child 6332 019660f4cc2b
permissions -rwxr-xr-x
RenderCopyEx,rotation and flipping for all hardware/software backends (#1308)
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2012 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 #if !SDL_RENDER_DISABLED
    24 
    25 #include "../SDL_sysrender.h"
    26 #include "SDL_render_sw_c.h"
    27 #include "SDL_hints.h"
    28 
    29 #include "SDL_draw.h"
    30 #include "SDL_blendfillrect.h"
    31 #include "SDL_blendline.h"
    32 #include "SDL_blendpoint.h"
    33 #include "SDL_drawline.h"
    34 #include "SDL_drawpoint.h"
    35 #include "SDL_rotate.h"
    36 
    37 /* SDL surface based renderer implementation */
    38 
    39 static SDL_Renderer *SW_CreateRenderer(SDL_Window * window, Uint32 flags);
    40 static void SW_WindowEvent(SDL_Renderer * renderer,
    41                            const SDL_WindowEvent *event);
    42 static int SW_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture);
    43 static int SW_SetTextureColorMod(SDL_Renderer * renderer,
    44                                  SDL_Texture * texture);
    45 static int SW_SetTextureAlphaMod(SDL_Renderer * renderer,
    46                                  SDL_Texture * texture);
    47 static int SW_SetTextureBlendMode(SDL_Renderer * renderer,
    48                                   SDL_Texture * texture);
    49 static int SW_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
    50                             const SDL_Rect * rect, const void *pixels,
    51                             int pitch);
    52 static int SW_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture,
    53                           const SDL_Rect * rect, void **pixels, int *pitch);
    54 static void SW_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture);
    55 static int SW_SetRenderTarget(SDL_Renderer * renderer, SDL_Texture * texture);
    56 static int SW_UpdateViewport(SDL_Renderer * renderer);
    57 static int SW_RenderClear(SDL_Renderer * renderer);
    58 static int SW_RenderDrawPoints(SDL_Renderer * renderer,
    59                                const SDL_Point * points, int count);
    60 static int SW_RenderDrawLines(SDL_Renderer * renderer,
    61                               const SDL_Point * points, int count);
    62 static int SW_RenderFillRects(SDL_Renderer * renderer,
    63                               const SDL_Rect * rects, int count);
    64 static int SW_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
    65                          const SDL_Rect * srcrect, const SDL_Rect * dstrect);
    66 static int SW_RenderCopyEx(SDL_Renderer * renderer, SDL_Texture * texture,
    67                           const SDL_Rect * srcrect, const SDL_Rect * dstrect,
    68                           const double angle, const SDL_Point * center, const SDL_RendererFlip flip);
    69 static int SW_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
    70                                Uint32 format, void * pixels, int pitch);
    71 static void SW_RenderPresent(SDL_Renderer * renderer);
    72 static void SW_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture);
    73 static void SW_DestroyRenderer(SDL_Renderer * renderer);
    74 
    75 
    76 SDL_RenderDriver SW_RenderDriver = {
    77     SW_CreateRenderer,
    78     {
    79      "software",
    80      SDL_RENDERER_SOFTWARE | SDL_RENDERER_TARGETTEXTURE,
    81      8,
    82      {
    83       SDL_PIXELFORMAT_RGB555,
    84       SDL_PIXELFORMAT_RGB565,
    85       SDL_PIXELFORMAT_RGB888,
    86       SDL_PIXELFORMAT_BGR888,
    87       SDL_PIXELFORMAT_ARGB8888,
    88       SDL_PIXELFORMAT_RGBA8888,
    89       SDL_PIXELFORMAT_ABGR8888,
    90       SDL_PIXELFORMAT_BGRA8888
    91      },
    92      0,
    93      0}
    94 };
    95 
    96 typedef struct
    97 {
    98     SDL_Surface *surface;
    99     SDL_Surface *window;
   100 } SW_RenderData;
   101 
   102 
   103 static SDL_Surface *
   104 SW_ActivateRenderer(SDL_Renderer * renderer)
   105 {
   106     SW_RenderData *data = (SW_RenderData *) renderer->driverdata;
   107 
   108     if (!data->surface) {
   109         data->surface = data->window;
   110     }
   111     if (!data->surface) {
   112         data->surface = data->window = SDL_GetWindowSurface(renderer->window);
   113 
   114         SW_UpdateViewport(renderer);
   115     }
   116     return data->surface;
   117 }
   118 
   119 SDL_Renderer *
   120 SW_CreateRendererForSurface(SDL_Surface * surface)
   121 {
   122     SDL_Renderer *renderer;
   123     SW_RenderData *data;
   124 
   125     if (!surface) {
   126         SDL_SetError("Can't create renderer for NULL surface");
   127         return NULL;
   128     }
   129 
   130     renderer = (SDL_Renderer *) SDL_calloc(1, sizeof(*renderer));
   131     if (!renderer) {
   132         SDL_OutOfMemory();
   133         return NULL;
   134     }
   135 
   136     data = (SW_RenderData *) SDL_calloc(1, sizeof(*data));
   137     if (!data) {
   138         SW_DestroyRenderer(renderer);
   139         SDL_OutOfMemory();
   140         return NULL;
   141     }
   142     data->surface = surface;
   143 
   144     renderer->WindowEvent = SW_WindowEvent;
   145     renderer->CreateTexture = SW_CreateTexture;
   146     renderer->SetTextureColorMod = SW_SetTextureColorMod;
   147     renderer->SetTextureAlphaMod = SW_SetTextureAlphaMod;
   148     renderer->SetTextureBlendMode = SW_SetTextureBlendMode;
   149     renderer->UpdateTexture = SW_UpdateTexture;
   150     renderer->LockTexture = SW_LockTexture;
   151     renderer->UnlockTexture = SW_UnlockTexture;
   152     renderer->SetRenderTarget = SW_SetRenderTarget;
   153     renderer->UpdateViewport = SW_UpdateViewport;
   154     renderer->RenderClear = SW_RenderClear;
   155     renderer->RenderDrawPoints = SW_RenderDrawPoints;
   156     renderer->RenderDrawLines = SW_RenderDrawLines;
   157     renderer->RenderFillRects = SW_RenderFillRects;
   158     renderer->RenderCopy = SW_RenderCopy;
   159     renderer->RenderCopyEx = SW_RenderCopyEx;
   160     renderer->RenderReadPixels = SW_RenderReadPixels;
   161     renderer->RenderPresent = SW_RenderPresent;
   162     renderer->DestroyTexture = SW_DestroyTexture;
   163     renderer->DestroyRenderer = SW_DestroyRenderer;
   164     renderer->info = SW_RenderDriver.info;
   165     renderer->driverdata = data;
   166 
   167     SW_ActivateRenderer(renderer);
   168 
   169     return renderer;
   170 }
   171 
   172 SDL_Renderer *
   173 SW_CreateRenderer(SDL_Window * window, Uint32 flags)
   174 {
   175     SDL_Surface *surface;
   176 
   177     surface = SDL_GetWindowSurface(window);
   178     if (!surface) {
   179         return NULL;
   180     }
   181     return SW_CreateRendererForSurface(surface);
   182 }
   183 
   184 static void
   185 SW_WindowEvent(SDL_Renderer * renderer, const SDL_WindowEvent *event)
   186 {
   187     SW_RenderData *data = (SW_RenderData *) renderer->driverdata;
   188 
   189     if (event->event == SDL_WINDOWEVENT_SIZE_CHANGED) {
   190         data->surface = NULL;
   191         data->window = NULL;
   192     }
   193 }
   194 
   195 static int
   196 SW_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture)
   197 {
   198     int bpp;
   199     Uint32 Rmask, Gmask, Bmask, Amask;
   200 
   201     if (!SDL_PixelFormatEnumToMasks
   202         (texture->format, &bpp, &Rmask, &Gmask, &Bmask, &Amask)) {
   203         SDL_SetError("Unknown texture format");
   204         return -1;
   205     }
   206 
   207     texture->driverdata =
   208         SDL_CreateRGBSurface(0, texture->w, texture->h, bpp, Rmask, Gmask,
   209                              Bmask, Amask);
   210     SDL_SetSurfaceColorMod(texture->driverdata, texture->r, texture->g,
   211                            texture->b);
   212     SDL_SetSurfaceAlphaMod(texture->driverdata, texture->a);
   213     SDL_SetSurfaceBlendMode(texture->driverdata, texture->blendMode);
   214 
   215     if (texture->access == SDL_TEXTUREACCESS_STATIC) {
   216         SDL_SetSurfaceRLE(texture->driverdata, 1);
   217     }
   218 
   219     if (!texture->driverdata) {
   220         return -1;
   221     }
   222     return 0;
   223 }
   224 
   225 static int
   226 SW_SetTextureColorMod(SDL_Renderer * renderer, SDL_Texture * texture)
   227 {
   228     SDL_Surface *surface = (SDL_Surface *) texture->driverdata;
   229     return SDL_SetSurfaceColorMod(surface, texture->r, texture->g,
   230                                   texture->b);
   231 }
   232 
   233 static int
   234 SW_SetTextureAlphaMod(SDL_Renderer * renderer, SDL_Texture * texture)
   235 {
   236     SDL_Surface *surface = (SDL_Surface *) texture->driverdata;
   237     return SDL_SetSurfaceAlphaMod(surface, texture->a);
   238 }
   239 
   240 static int
   241 SW_SetTextureBlendMode(SDL_Renderer * renderer, SDL_Texture * texture)
   242 {
   243     SDL_Surface *surface = (SDL_Surface *) texture->driverdata;
   244     return SDL_SetSurfaceBlendMode(surface, texture->blendMode);
   245 }
   246 
   247 static int
   248 SW_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
   249                  const SDL_Rect * rect, const void *pixels, int pitch)
   250 {
   251     SDL_Surface *surface = (SDL_Surface *) texture->driverdata;
   252     Uint8 *src, *dst;
   253     int row;
   254     size_t length;
   255 
   256     if(SDL_MUSTLOCK(surface))
   257         SDL_LockSurface(surface);
   258     src = (Uint8 *) pixels;
   259     dst = (Uint8 *) surface->pixels +
   260                         rect->y * surface->pitch +
   261                         rect->x * surface->format->BytesPerPixel;
   262     length = rect->w * surface->format->BytesPerPixel;
   263     for (row = 0; row < rect->h; ++row) {
   264         SDL_memcpy(dst, src, length);
   265         src += pitch;
   266         dst += surface->pitch;
   267     }
   268     if(SDL_MUSTLOCK(surface))
   269         SDL_UnlockSurface(surface);
   270     return 0;
   271 }
   272 
   273 static int
   274 SW_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture,
   275                const SDL_Rect * rect, void **pixels, int *pitch)
   276 {
   277     SDL_Surface *surface = (SDL_Surface *) texture->driverdata;
   278 
   279     *pixels =
   280         (void *) ((Uint8 *) surface->pixels + rect->y * surface->pitch +
   281                   rect->x * surface->format->BytesPerPixel);
   282     *pitch = surface->pitch;
   283     return 0;
   284 }
   285 
   286 static void
   287 SW_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture)
   288 {
   289 }
   290 
   291 static int
   292 SW_SetRenderTarget(SDL_Renderer * renderer, SDL_Texture * texture)
   293 {
   294     SW_RenderData *data = (SW_RenderData *) renderer->driverdata;
   295 
   296     if (texture ) {
   297         data->surface = (SDL_Surface *) texture->driverdata;
   298     } else {
   299         data->surface = data->window;
   300     }
   301     return 0;
   302 }
   303 
   304 static int
   305 SW_UpdateViewport(SDL_Renderer * renderer)
   306 {
   307     SW_RenderData *data = (SW_RenderData *) renderer->driverdata;
   308     SDL_Surface *surface = data->surface;
   309 
   310     if (!surface) {
   311         /* We'll update the viewport after we recreate the surface */
   312         return 0;
   313     }
   314 
   315     if (!renderer->viewport.w && !renderer->viewport.h) {
   316         /* There may be no window, so update the viewport directly */
   317         renderer->viewport.w = surface->w;
   318         renderer->viewport.h = surface->h;
   319     }
   320     SDL_SetClipRect(data->surface, &renderer->viewport);
   321     return 0;
   322 }
   323 
   324 static int
   325 SW_RenderClear(SDL_Renderer * renderer)
   326 {
   327     SDL_Surface *surface = SW_ActivateRenderer(renderer);
   328     Uint32 color;
   329     SDL_Rect clip_rect;
   330 
   331     if (!surface) {
   332         return -1;
   333     }
   334 
   335     color = SDL_MapRGBA(surface->format,
   336                         renderer->r, renderer->g, renderer->b, renderer->a);
   337 
   338     /* By definition the clear ignores the clip rect */
   339     clip_rect = surface->clip_rect;
   340     SDL_SetClipRect(surface, NULL);
   341     SDL_FillRect(surface, NULL, color);
   342     SDL_SetClipRect(surface, &clip_rect);
   343     return 0;
   344 }
   345 
   346 static int
   347 SW_RenderDrawPoints(SDL_Renderer * renderer, const SDL_Point * points,
   348                     int count)
   349 {
   350     SDL_Surface *surface = SW_ActivateRenderer(renderer);
   351     SDL_Point *temp = NULL;
   352     int status;
   353 
   354     if (!surface) {
   355         return -1;
   356     }
   357 
   358     if (renderer->viewport.x || renderer->viewport.y) {
   359         int i;
   360         int x = renderer->viewport.x;
   361         int y = renderer->viewport.y;
   362 
   363         temp = SDL_stack_alloc(SDL_Point, count);
   364         for (i = 0; i < count; ++i) {
   365             temp[i].x = x + points[i].x;
   366             temp[i].y = y + points[i].x;
   367         }
   368         points = temp;
   369     }
   370 
   371     /* Draw the points! */
   372     if (renderer->blendMode == SDL_BLENDMODE_NONE) {
   373         Uint32 color = SDL_MapRGBA(surface->format,
   374                                    renderer->r, renderer->g, renderer->b,
   375                                    renderer->a);
   376 
   377         status = SDL_DrawPoints(surface, points, count, color);
   378     } else {
   379         status = SDL_BlendPoints(surface, points, count,
   380                                 renderer->blendMode,
   381                                 renderer->r, renderer->g, renderer->b,
   382                                 renderer->a);
   383     }
   384 
   385     if (temp) {
   386         SDL_stack_free(temp);
   387     }
   388     return status;
   389 }
   390 
   391 static int
   392 SW_RenderDrawLines(SDL_Renderer * renderer, const SDL_Point * points,
   393                    int count)
   394 {
   395     SDL_Surface *surface = SW_ActivateRenderer(renderer);
   396     SDL_Point *temp = NULL;
   397     int status;
   398 
   399     if (!surface) {
   400         return -1;
   401     }
   402 
   403     if (renderer->viewport.x || renderer->viewport.y) {
   404         int i;
   405         int x = renderer->viewport.x;
   406         int y = renderer->viewport.y;
   407 
   408         temp = SDL_stack_alloc(SDL_Point, count);
   409         for (i = 0; i < count; ++i) {
   410             temp[i].x = x + points[i].x;
   411             temp[i].y = y + points[i].y;
   412         }
   413         points = temp;
   414     }
   415 
   416     /* Draw the lines! */
   417     if (renderer->blendMode == SDL_BLENDMODE_NONE) {
   418         Uint32 color = SDL_MapRGBA(surface->format,
   419                                    renderer->r, renderer->g, renderer->b,
   420                                    renderer->a);
   421 
   422         status = SDL_DrawLines(surface, points, count, color);
   423     } else {
   424         status = SDL_BlendLines(surface, points, count,
   425                                 renderer->blendMode,
   426                                 renderer->r, renderer->g, renderer->b,
   427                                 renderer->a);
   428     }
   429 
   430     if (temp) {
   431         SDL_stack_free(temp);
   432     }
   433     return status;
   434 }
   435 
   436 static int
   437 SW_RenderFillRects(SDL_Renderer * renderer, const SDL_Rect * rects, int count)
   438 {
   439     SDL_Surface *surface = SW_ActivateRenderer(renderer);
   440     SDL_Rect *temp = NULL;
   441     int status;
   442 
   443     if (!surface) {
   444         return -1;
   445     }
   446 
   447     if (renderer->viewport.x || renderer->viewport.y) {
   448         int i;
   449         int x = renderer->viewport.x;
   450         int y = renderer->viewport.y;
   451 
   452         temp = SDL_stack_alloc(SDL_Rect, count);
   453         for (i = 0; i < count; ++i) {
   454             temp[i].x = x + rects[i].x;
   455             temp[i].y = y + rects[i].y;
   456             temp[i].w = rects[i].w;
   457             temp[i].h = rects[i].h;
   458         }
   459         rects = temp;
   460     }
   461 
   462     if (renderer->blendMode == SDL_BLENDMODE_NONE) {
   463         Uint32 color = SDL_MapRGBA(surface->format,
   464                                    renderer->r, renderer->g, renderer->b,
   465                                    renderer->a);
   466         status = SDL_FillRects(surface, rects, count, color);
   467     } else {
   468         status = SDL_BlendFillRects(surface, rects, count,
   469                                     renderer->blendMode,
   470                                     renderer->r, renderer->g, renderer->b,
   471                                     renderer->a);
   472     }
   473 
   474     if (temp) {
   475         SDL_stack_free(temp);
   476     }
   477     return status;
   478 }
   479 
   480 static int
   481 SW_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
   482               const SDL_Rect * srcrect, const SDL_Rect * dstrect)
   483 {
   484     SDL_Surface *surface = SW_ActivateRenderer(renderer);
   485     SDL_Surface *src = (SDL_Surface *) texture->driverdata;
   486     SDL_Rect final_rect = *dstrect;
   487 
   488     if (!surface) {
   489         return -1;
   490     }
   491 
   492     if (renderer->viewport.x || renderer->viewport.y) {
   493         final_rect.x += renderer->viewport.x;
   494         final_rect.y += renderer->viewport.y;
   495     }
   496     if ( srcrect->w == final_rect.w && srcrect->h == final_rect.h ) {
   497         return SDL_BlitSurface(src, srcrect, surface, &final_rect);
   498     } else {
   499         return SDL_BlitScaled(src, srcrect, surface, &final_rect);
   500     }
   501 }
   502 
   503 static int
   504 GetScaleQuality(void)
   505 {
   506     const char *hint = SDL_GetHint(SDL_HINT_RENDER_SCALE_QUALITY);
   507 
   508     if (!hint || *hint == '0' || SDL_strcasecmp(hint, "nearest") == 0) {
   509         return 0;
   510     } else {
   511         return 1;
   512     }
   513 }
   514 
   515 static int
   516 SW_RenderCopyEx(SDL_Renderer * renderer, SDL_Texture * texture,
   517                 const SDL_Rect * srcrect, const SDL_Rect * dstrect,
   518                 const double angle, const SDL_Point * center, const SDL_RendererFlip flip)
   519 {
   520     SDL_Surface *surface = SW_ActivateRenderer(renderer);
   521     SDL_Surface *src = (SDL_Surface *) texture->driverdata;
   522     SDL_Rect final_rect = *dstrect, tmp_rect;
   523     SDL_Surface *surface_rotated, *surface_scaled;
   524     SDL_Point final_rect_center;
   525     Uint32 colorkey;
   526     int retval, dstwidth, dstheight, abscenterx, abscentery;
   527     double cangle, sangle, px, py, p1x, p1y, p2x, p2y, p3x, p3y, p4x, p4y;
   528 
   529     if (!surface) {
   530         return -1;
   531     }
   532 
   533     if (renderer->viewport.x || renderer->viewport.y) {
   534         final_rect.x += renderer->viewport.x;
   535         final_rect.y += renderer->viewport.y;
   536     }
   537 
   538     surface_scaled = SDL_CreateRGBSurface(SDL_SWSURFACE, final_rect.w, final_rect.h, src->format->BitsPerPixel,
   539                                           src->format->Rmask, src->format->Gmask,
   540                                           src->format->Bmask, src->format->Amask );
   541     SDL_GetColorKey(src, &colorkey);
   542     SDL_SetColorKey(surface_scaled, SDL_TRUE, colorkey);
   543     tmp_rect = final_rect;
   544     tmp_rect.x = 0;
   545     tmp_rect.y = 0;
   546     if (surface_scaled) {
   547         retval = SDL_BlitScaled(src, srcrect, surface_scaled, &tmp_rect);
   548         if (!retval) {
   549             _rotozoomSurfaceSizeTrig(tmp_rect.w, tmp_rect.h, -angle, &dstwidth, &dstheight, &cangle, &sangle);
   550             surface_rotated = _rotateSurface(surface_scaled, -angle, dstwidth/2, dstheight/2, GetScaleQuality(), flip & SDL_FLIP_HORIZONTAL, flip & SDL_FLIP_VERTICAL, dstwidth, dstheight, cangle, sangle);
   551             if(surface_rotated) {
   552                 /* Find out where the new origin is by rotating the four final_rect points around the center and then taking the extremes */
   553                 abscenterx = final_rect.x + center->x;
   554                 abscentery = final_rect.y + center->y;
   555                 /* Compensate the angle inversion to match the behaviour of the other backends */
   556                 sangle = -sangle;
   557 
   558                 /* Top Left */
   559                 px = final_rect.x - abscenterx;
   560                 py = final_rect.y - abscentery;
   561                 p1x = px * cangle - py * sangle + abscenterx;
   562                 p1y = px * sangle + py * cangle + abscentery;
   563 
   564                 /* Top Right */
   565                 px = final_rect.x + final_rect.w - abscenterx;
   566                 py = final_rect.y - abscentery;
   567                 p2x = px * cangle - py * sangle + abscenterx;
   568                 p2y = px * sangle + py * cangle + abscentery;
   569 
   570                 /* Bottom Left */
   571                 px = final_rect.x - abscenterx;
   572                 py = final_rect.y + final_rect.h - abscentery;
   573                 p3x = px * cangle - py * sangle + abscenterx;
   574                 p3y = px * sangle + py * cangle + abscentery;
   575 
   576                 /* Bottom Right */
   577                 px = final_rect.x + final_rect.w - abscenterx;
   578                 py = final_rect.y + final_rect.h - abscentery;
   579                 p4x = px * cangle - py * sangle + abscenterx;
   580                 p4y = px * sangle + py * cangle + abscentery;
   581 
   582                 tmp_rect.x = (int)MIN(MIN(p1x, p2x), MIN(p3x, p4x));
   583                 tmp_rect.y = (int)MIN(MIN(p1y, p2y), MIN(p3y, p4y));
   584                 tmp_rect.w = dstwidth;
   585                 tmp_rect.h = dstheight;
   586 
   587                 retval = SDL_BlitSurface(surface_rotated, NULL, surface, &tmp_rect);
   588                 SDL_FreeSurface(surface_scaled);
   589                 SDL_FreeSurface(surface_rotated);
   590                 return retval;
   591             }
   592         }
   593         return retval;
   594     }
   595 
   596     return -1;
   597 }
   598 
   599 static int
   600 SW_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
   601                     Uint32 format, void * pixels, int pitch)
   602 {
   603     SDL_Surface *surface = SW_ActivateRenderer(renderer);
   604     Uint32 src_format;
   605     void *src_pixels;
   606     SDL_Rect final_rect;
   607 
   608     if (!surface) {
   609         return -1;
   610     }
   611 
   612     if (renderer->viewport.x || renderer->viewport.y) {
   613         final_rect.x = renderer->viewport.x + rect->x;
   614         final_rect.y = renderer->viewport.y + rect->y;
   615         final_rect.w = rect->w;
   616         final_rect.h = rect->h;
   617         rect = &final_rect;
   618     }
   619 
   620     if (rect->x < 0 || rect->x+rect->w > surface->w ||
   621         rect->y < 0 || rect->y+rect->h > surface->h) {
   622         SDL_SetError("Tried to read outside of surface bounds");
   623         return -1;
   624     }
   625 
   626     src_format = surface->format->format;
   627     src_pixels = (void*)((Uint8 *) surface->pixels +
   628                     rect->y * surface->pitch +
   629                     rect->x * surface->format->BytesPerPixel);
   630 
   631     return SDL_ConvertPixels(rect->w, rect->h,
   632                              src_format, src_pixels, surface->pitch,
   633                              format, pixels, pitch);
   634 }
   635 
   636 static void
   637 SW_RenderPresent(SDL_Renderer * renderer)
   638 {
   639     SDL_Window *window = renderer->window;
   640 
   641     if (window) {
   642         SDL_UpdateWindowSurface(window);
   643     }
   644 }
   645 
   646 static void
   647 SW_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture)
   648 {
   649     SDL_Surface *surface = (SDL_Surface *) texture->driverdata;
   650 
   651     SDL_FreeSurface(surface);
   652 }
   653 
   654 static void
   655 SW_DestroyRenderer(SDL_Renderer * renderer)
   656 {
   657     SW_RenderData *data = (SW_RenderData *) renderer->driverdata;
   658 
   659     if (data) {
   660         SDL_free(data);
   661     }
   662     SDL_free(renderer);
   663 }
   664 
   665 #endif /* !SDL_RENDER_DISABLED */
   666 
   667 /* vi: set ts=4 sw=4 expandtab: */