src/render/software/SDL_render_sw.c
author Sam Lantinga <slouken@libsdl.org>
Wed, 29 May 2013 03:07:55 -0700
changeset 7239 04dda95ba22c
parent 7141 e276777b4247
child 7322 5b94da2650a6
permissions -rw-r--r--
Fixed bug 1622 - SDL_RenderSetViewport with empty SDL_Rect raises wrong error for OpenGL rendering backend

It's now legal to set an empty viewport rect - it will prevent any rendering.

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