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