src/render/software/SDL_render_sw.c
author Sam Lantinga <slouken@libsdl.org>
Fri, 19 Jun 2015 22:12:47 -0700
changeset 9760 2f5a57f86e24
parent 9619 b94b6d0bff0f
child 9762 5c4a85c5b648
permissions -rw-r--r--
[mq]: 3027_rleperf.diff
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2015 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_internal.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_ARGB8888,
    86       SDL_PIXELFORMAT_ABGR8888,
    87       SDL_PIXELFORMAT_RGBA8888,
    88       SDL_PIXELFORMAT_BGRA8888,
    89       SDL_PIXELFORMAT_RGB888,
    90       SDL_PIXELFORMAT_BGR888,
    91       SDL_PIXELFORMAT_RGB565,
    92       SDL_PIXELFORMAT_RGB555
    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 
   118             SW_UpdateViewport(renderer);
   119             SW_UpdateClipRect(renderer);
   120         }
   121     }
   122     return data->surface;
   123 }
   124 
   125 SDL_Renderer *
   126 SW_CreateRendererForSurface(SDL_Surface * surface)
   127 {
   128     SDL_Renderer *renderer;
   129     SW_RenderData *data;
   130 
   131     if (!surface) {
   132         SDL_SetError("Can't create renderer for NULL surface");
   133         return NULL;
   134     }
   135 
   136     renderer = (SDL_Renderer *) SDL_calloc(1, sizeof(*renderer));
   137     if (!renderer) {
   138         SDL_OutOfMemory();
   139         return NULL;
   140     }
   141 
   142     data = (SW_RenderData *) SDL_calloc(1, sizeof(*data));
   143     if (!data) {
   144         SW_DestroyRenderer(renderer);
   145         SDL_OutOfMemory();
   146         return NULL;
   147     }
   148     data->surface = surface;
   149     data->window = 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     /* If the color mod is ever enabled (non-white), permanently disable RLE (which doesn't support
   257      * color mod) to avoid potentially frequent RLE encoding/decoding.
   258      */
   259     if ((texture->r & texture->g & texture->b) != 255) {
   260         SDL_SetSurfaceRLE(surface, 0);
   261     }
   262     return SDL_SetSurfaceColorMod(surface, texture->r, texture->g,
   263                                   texture->b);
   264 }
   265 
   266 static int
   267 SW_SetTextureAlphaMod(SDL_Renderer * renderer, SDL_Texture * texture)
   268 {
   269     SDL_Surface *surface = (SDL_Surface *) texture->driverdata;
   270     /* If the texture ever has multiple alpha values (surface alpha plus alpha channel), permanently
   271      * disable RLE (which doesn't support this) to avoid potentially frequent RLE encoding/decoding.
   272      */
   273     if (texture->a != 255 && surface->format->Amask) {
   274         SDL_SetSurfaceRLE(surface, 0);
   275     }
   276     return SDL_SetSurfaceAlphaMod(surface, texture->a);
   277 }
   278 
   279 static int
   280 SW_SetTextureBlendMode(SDL_Renderer * renderer, SDL_Texture * texture)
   281 {
   282     SDL_Surface *surface = (SDL_Surface *) texture->driverdata;
   283     /* If add or mod blending are ever enabled, permanently disable RLE (which doesn't support
   284      * them) to avoid potentially frequent RLE encoding/decoding.
   285      */
   286     if ((texture->blendMode == SDL_BLENDMODE_ADD || texture->blendMode == SDL_BLENDMODE_MOD)) {
   287         SDL_SetSurfaceRLE(surface, 0);
   288     }
   289     return SDL_SetSurfaceBlendMode(surface, texture->blendMode);
   290 }
   291 
   292 static int
   293 SW_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
   294                  const SDL_Rect * rect, const void *pixels, int pitch)
   295 {
   296     SDL_Surface *surface = (SDL_Surface *) texture->driverdata;
   297     Uint8 *src, *dst;
   298     int row;
   299     size_t length;
   300 
   301     if(SDL_MUSTLOCK(surface))
   302         SDL_LockSurface(surface);
   303     src = (Uint8 *) pixels;
   304     dst = (Uint8 *) surface->pixels +
   305                         rect->y * surface->pitch +
   306                         rect->x * surface->format->BytesPerPixel;
   307     length = rect->w * surface->format->BytesPerPixel;
   308     for (row = 0; row < rect->h; ++row) {
   309         SDL_memcpy(dst, src, length);
   310         src += pitch;
   311         dst += surface->pitch;
   312     }
   313     if(SDL_MUSTLOCK(surface))
   314         SDL_UnlockSurface(surface);
   315     return 0;
   316 }
   317 
   318 static int
   319 SW_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture,
   320                const SDL_Rect * rect, void **pixels, int *pitch)
   321 {
   322     SDL_Surface *surface = (SDL_Surface *) texture->driverdata;
   323 
   324     *pixels =
   325         (void *) ((Uint8 *) surface->pixels + rect->y * surface->pitch +
   326                   rect->x * surface->format->BytesPerPixel);
   327     *pitch = surface->pitch;
   328     return 0;
   329 }
   330 
   331 static void
   332 SW_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture)
   333 {
   334 }
   335 
   336 static int
   337 SW_SetRenderTarget(SDL_Renderer * renderer, SDL_Texture * texture)
   338 {
   339     SW_RenderData *data = (SW_RenderData *) renderer->driverdata;
   340 
   341     if (texture ) {
   342         data->surface = (SDL_Surface *) texture->driverdata;
   343     } else {
   344         data->surface = data->window;
   345     }
   346     return 0;
   347 }
   348 
   349 static int
   350 SW_UpdateViewport(SDL_Renderer * renderer)
   351 {
   352     SW_RenderData *data = (SW_RenderData *) renderer->driverdata;
   353     SDL_Surface *surface = data->surface;
   354 
   355     if (!surface) {
   356         /* We'll update the viewport after we recreate the surface */
   357         return 0;
   358     }
   359 
   360     SDL_SetClipRect(data->surface, &renderer->viewport);
   361     return 0;
   362 }
   363 
   364 static int
   365 SW_UpdateClipRect(SDL_Renderer * renderer)
   366 {
   367     SW_RenderData *data = (SW_RenderData *) renderer->driverdata;
   368     SDL_Surface *surface = data->surface;
   369     if (surface) {
   370         if (renderer->clipping_enabled) {
   371             SDL_SetClipRect(surface, &renderer->clip_rect);
   372         } else {
   373             SDL_SetClipRect(surface, NULL);
   374         }
   375     }
   376     return 0;
   377 }
   378 
   379 static int
   380 SW_RenderClear(SDL_Renderer * renderer)
   381 {
   382     SDL_Surface *surface = SW_ActivateRenderer(renderer);
   383     Uint32 color;
   384     SDL_Rect clip_rect;
   385 
   386     if (!surface) {
   387         return -1;
   388     }
   389 
   390     color = SDL_MapRGBA(surface->format,
   391                         renderer->r, renderer->g, renderer->b, renderer->a);
   392 
   393     /* By definition the clear ignores the clip rect */
   394     clip_rect = surface->clip_rect;
   395     SDL_SetClipRect(surface, NULL);
   396     SDL_FillRect(surface, NULL, color);
   397     SDL_SetClipRect(surface, &clip_rect);
   398     return 0;
   399 }
   400 
   401 static int
   402 SW_RenderDrawPoints(SDL_Renderer * renderer, const SDL_FPoint * points,
   403                     int count)
   404 {
   405     SDL_Surface *surface = SW_ActivateRenderer(renderer);
   406     SDL_Point *final_points;
   407     int i, status;
   408 
   409     if (!surface) {
   410         return -1;
   411     }
   412 
   413     final_points = SDL_stack_alloc(SDL_Point, count);
   414     if (!final_points) {
   415         return SDL_OutOfMemory();
   416     }
   417     if (renderer->viewport.x || renderer->viewport.y) {
   418         int x = renderer->viewport.x;
   419         int y = renderer->viewport.y;
   420 
   421         for (i = 0; i < count; ++i) {
   422             final_points[i].x = (int)(x + points[i].x);
   423             final_points[i].y = (int)(y + points[i].y);
   424         }
   425     } else {
   426         for (i = 0; i < count; ++i) {
   427             final_points[i].x = (int)points[i].x;
   428             final_points[i].y = (int)points[i].y;
   429         }
   430     }
   431 
   432     /* Draw the points! */
   433     if (renderer->blendMode == SDL_BLENDMODE_NONE) {
   434         Uint32 color = SDL_MapRGBA(surface->format,
   435                                    renderer->r, renderer->g, renderer->b,
   436                                    renderer->a);
   437 
   438         status = SDL_DrawPoints(surface, final_points, count, color);
   439     } else {
   440         status = SDL_BlendPoints(surface, final_points, count,
   441                                 renderer->blendMode,
   442                                 renderer->r, renderer->g, renderer->b,
   443                                 renderer->a);
   444     }
   445     SDL_stack_free(final_points);
   446 
   447     return status;
   448 }
   449 
   450 static int
   451 SW_RenderDrawLines(SDL_Renderer * renderer, const SDL_FPoint * points,
   452                    int count)
   453 {
   454     SDL_Surface *surface = SW_ActivateRenderer(renderer);
   455     SDL_Point *final_points;
   456     int i, status;
   457 
   458     if (!surface) {
   459         return -1;
   460     }
   461 
   462     final_points = SDL_stack_alloc(SDL_Point, count);
   463     if (!final_points) {
   464         return SDL_OutOfMemory();
   465     }
   466     if (renderer->viewport.x || renderer->viewport.y) {
   467         int x = renderer->viewport.x;
   468         int y = renderer->viewport.y;
   469 
   470         for (i = 0; i < count; ++i) {
   471             final_points[i].x = (int)(x + points[i].x);
   472             final_points[i].y = (int)(y + points[i].y);
   473         }
   474     } else {
   475         for (i = 0; i < count; ++i) {
   476             final_points[i].x = (int)points[i].x;
   477             final_points[i].y = (int)points[i].y;
   478         }
   479     }
   480 
   481     /* Draw the lines! */
   482     if (renderer->blendMode == SDL_BLENDMODE_NONE) {
   483         Uint32 color = SDL_MapRGBA(surface->format,
   484                                    renderer->r, renderer->g, renderer->b,
   485                                    renderer->a);
   486 
   487         status = SDL_DrawLines(surface, final_points, count, color);
   488     } else {
   489         status = SDL_BlendLines(surface, final_points, count,
   490                                 renderer->blendMode,
   491                                 renderer->r, renderer->g, renderer->b,
   492                                 renderer->a);
   493     }
   494     SDL_stack_free(final_points);
   495 
   496     return status;
   497 }
   498 
   499 static int
   500 SW_RenderFillRects(SDL_Renderer * renderer, const SDL_FRect * rects, int count)
   501 {
   502     SDL_Surface *surface = SW_ActivateRenderer(renderer);
   503     SDL_Rect *final_rects;
   504     int i, status;
   505 
   506     if (!surface) {
   507         return -1;
   508     }
   509 
   510     final_rects = SDL_stack_alloc(SDL_Rect, count);
   511     if (!final_rects) {
   512         return SDL_OutOfMemory();
   513     }
   514     if (renderer->viewport.x || renderer->viewport.y) {
   515         int x = renderer->viewport.x;
   516         int y = renderer->viewport.y;
   517 
   518         for (i = 0; i < count; ++i) {
   519             final_rects[i].x = (int)(x + rects[i].x);
   520             final_rects[i].y = (int)(y + rects[i].y);
   521             final_rects[i].w = SDL_max((int)rects[i].w, 1);
   522             final_rects[i].h = SDL_max((int)rects[i].h, 1);
   523         }
   524     } else {
   525         for (i = 0; i < count; ++i) {
   526             final_rects[i].x = (int)rects[i].x;
   527             final_rects[i].y = (int)rects[i].y;
   528             final_rects[i].w = SDL_max((int)rects[i].w, 1);
   529             final_rects[i].h = SDL_max((int)rects[i].h, 1);
   530         }
   531     }
   532 
   533     if (renderer->blendMode == SDL_BLENDMODE_NONE) {
   534         Uint32 color = SDL_MapRGBA(surface->format,
   535                                    renderer->r, renderer->g, renderer->b,
   536                                    renderer->a);
   537         status = SDL_FillRects(surface, final_rects, count, color);
   538     } else {
   539         status = SDL_BlendFillRects(surface, final_rects, count,
   540                                     renderer->blendMode,
   541                                     renderer->r, renderer->g, renderer->b,
   542                                     renderer->a);
   543     }
   544     SDL_stack_free(final_rects);
   545 
   546     return status;
   547 }
   548 
   549 static int
   550 SW_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
   551               const SDL_Rect * srcrect, const SDL_FRect * dstrect)
   552 {
   553     SDL_Surface *surface = SW_ActivateRenderer(renderer);
   554     SDL_Surface *src = (SDL_Surface *) texture->driverdata;
   555     SDL_Rect final_rect;
   556 
   557     if (!surface) {
   558         return -1;
   559     }
   560 
   561     if (renderer->viewport.x || renderer->viewport.y) {
   562         final_rect.x = (int)(renderer->viewport.x + dstrect->x);
   563         final_rect.y = (int)(renderer->viewport.y + dstrect->y);
   564     } else {
   565         final_rect.x = (int)dstrect->x;
   566         final_rect.y = (int)dstrect->y;
   567     }
   568     final_rect.w = (int)dstrect->w;
   569     final_rect.h = (int)dstrect->h;
   570 
   571     if ( srcrect->w == final_rect.w && srcrect->h == final_rect.h ) {
   572         return SDL_BlitSurface(src, srcrect, surface, &final_rect);
   573     } else {
   574         /* If scaling is ever done, permanently disable RLE (which doesn't support scaling)
   575          * to avoid potentially frequent RLE encoding/decoding.
   576          */
   577         SDL_SetSurfaceRLE(surface, 0);
   578         return SDL_BlitScaled(src, srcrect, surface, &final_rect);
   579     }
   580 }
   581 
   582 static int
   583 GetScaleQuality(void)
   584 {
   585     const char *hint = SDL_GetHint(SDL_HINT_RENDER_SCALE_QUALITY);
   586 
   587     if (!hint || *hint == '0' || SDL_strcasecmp(hint, "nearest") == 0) {
   588         return 0;
   589     } else {
   590         return 1;
   591     }
   592 }
   593 
   594 static int
   595 SW_RenderCopyEx(SDL_Renderer * renderer, SDL_Texture * texture,
   596                 const SDL_Rect * srcrect, const SDL_FRect * dstrect,
   597                 const double angle, const SDL_FPoint * center, const SDL_RendererFlip flip)
   598 {
   599     SDL_Surface *surface = SW_ActivateRenderer(renderer);
   600     SDL_Surface *src = (SDL_Surface *) texture->driverdata;
   601     SDL_Rect final_rect, tmp_rect;
   602     SDL_Surface *surface_rotated, *surface_scaled;
   603     Uint32 colorkey;
   604     int retval, dstwidth, dstheight, abscenterx, abscentery;
   605     double cangle, sangle, px, py, p1x, p1y, p2x, p2y, p3x, p3y, p4x, p4y;
   606 
   607     if (!surface) {
   608         return -1;
   609     }
   610 
   611     if (renderer->viewport.x || renderer->viewport.y) {
   612         final_rect.x = (int)(renderer->viewport.x + dstrect->x);
   613         final_rect.y = (int)(renderer->viewport.y + dstrect->y);
   614     } else {
   615         final_rect.x = (int)dstrect->x;
   616         final_rect.y = (int)dstrect->y;
   617     }
   618     final_rect.w = (int)dstrect->w;
   619     final_rect.h = (int)dstrect->h;
   620 
   621     surface_scaled = SDL_CreateRGBSurface(SDL_SWSURFACE, final_rect.w, final_rect.h, src->format->BitsPerPixel,
   622                                           src->format->Rmask, src->format->Gmask,
   623                                           src->format->Bmask, src->format->Amask );
   624     if (surface_scaled) {
   625         SDL_GetColorKey(src, &colorkey);
   626         SDL_SetColorKey(surface_scaled, SDL_TRUE, colorkey);
   627         tmp_rect = final_rect;
   628         tmp_rect.x = 0;
   629         tmp_rect.y = 0;
   630 
   631         retval = SDL_BlitScaled(src, srcrect, surface_scaled, &tmp_rect);
   632         if (!retval) {
   633             SDLgfx_rotozoomSurfaceSizeTrig(tmp_rect.w, tmp_rect.h, -angle, &dstwidth, &dstheight, &cangle, &sangle);
   634             surface_rotated = SDLgfx_rotateSurface(surface_scaled, -angle, dstwidth/2, dstheight/2, GetScaleQuality(), flip & SDL_FLIP_HORIZONTAL, flip & SDL_FLIP_VERTICAL, dstwidth, dstheight, cangle, sangle);
   635             if(surface_rotated) {
   636                 /* Find out where the new origin is by rotating the four final_rect points around the center and then taking the extremes */
   637                 abscenterx = final_rect.x + (int)center->x;
   638                 abscentery = final_rect.y + (int)center->y;
   639                 /* Compensate the angle inversion to match the behaviour of the other backends */
   640                 sangle = -sangle;
   641 
   642                 /* Top Left */
   643                 px = final_rect.x - abscenterx;
   644                 py = final_rect.y - abscentery;
   645                 p1x = px * cangle - py * sangle + abscenterx;
   646                 p1y = px * sangle + py * cangle + abscentery;
   647 
   648                 /* Top Right */
   649                 px = final_rect.x + final_rect.w - abscenterx;
   650                 py = final_rect.y - abscentery;
   651                 p2x = px * cangle - py * sangle + abscenterx;
   652                 p2y = px * sangle + py * cangle + abscentery;
   653 
   654                 /* Bottom Left */
   655                 px = final_rect.x - abscenterx;
   656                 py = final_rect.y + final_rect.h - abscentery;
   657                 p3x = px * cangle - py * sangle + abscenterx;
   658                 p3y = px * sangle + py * cangle + abscentery;
   659 
   660                 /* Bottom Right */
   661                 px = final_rect.x + final_rect.w - abscenterx;
   662                 py = final_rect.y + final_rect.h - abscentery;
   663                 p4x = px * cangle - py * sangle + abscenterx;
   664                 p4y = px * sangle + py * cangle + abscentery;
   665 
   666                 tmp_rect.x = (int)MIN(MIN(p1x, p2x), MIN(p3x, p4x));
   667                 tmp_rect.y = (int)MIN(MIN(p1y, p2y), MIN(p3y, p4y));
   668                 tmp_rect.w = dstwidth;
   669                 tmp_rect.h = dstheight;
   670 
   671                 retval = SDL_BlitSurface(surface_rotated, NULL, surface, &tmp_rect);
   672                 SDL_FreeSurface(surface_scaled);
   673                 SDL_FreeSurface(surface_rotated);
   674                 return retval;
   675             }
   676         }
   677         return retval;
   678     }
   679 
   680     return -1;
   681 }
   682 
   683 static int
   684 SW_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
   685                     Uint32 format, void * pixels, int pitch)
   686 {
   687     SDL_Surface *surface = SW_ActivateRenderer(renderer);
   688     Uint32 src_format;
   689     void *src_pixels;
   690     SDL_Rect final_rect;
   691 
   692     if (!surface) {
   693         return -1;
   694     }
   695 
   696     if (renderer->viewport.x || renderer->viewport.y) {
   697         final_rect.x = renderer->viewport.x + rect->x;
   698         final_rect.y = renderer->viewport.y + rect->y;
   699         final_rect.w = rect->w;
   700         final_rect.h = rect->h;
   701         rect = &final_rect;
   702     }
   703 
   704     if (rect->x < 0 || rect->x+rect->w > surface->w ||
   705         rect->y < 0 || rect->y+rect->h > surface->h) {
   706         return SDL_SetError("Tried to read outside of surface bounds");
   707     }
   708 
   709     src_format = surface->format->format;
   710     src_pixels = (void*)((Uint8 *) surface->pixels +
   711                     rect->y * surface->pitch +
   712                     rect->x * surface->format->BytesPerPixel);
   713 
   714     return SDL_ConvertPixels(rect->w, rect->h,
   715                              src_format, src_pixels, surface->pitch,
   716                              format, pixels, pitch);
   717 }
   718 
   719 static void
   720 SW_RenderPresent(SDL_Renderer * renderer)
   721 {
   722     SDL_Window *window = renderer->window;
   723 
   724     if (window) {
   725         SDL_UpdateWindowSurface(window);
   726     }
   727 }
   728 
   729 static void
   730 SW_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture)
   731 {
   732     SDL_Surface *surface = (SDL_Surface *) texture->driverdata;
   733 
   734     SDL_FreeSurface(surface);
   735 }
   736 
   737 static void
   738 SW_DestroyRenderer(SDL_Renderer * renderer)
   739 {
   740     SW_RenderData *data = (SW_RenderData *) renderer->driverdata;
   741 
   742     SDL_free(data);
   743     SDL_free(renderer);
   744 }
   745 
   746 #endif /* !SDL_RENDER_DISABLED */
   747 
   748 /* vi: set ts=4 sw=4 expandtab: */