src/render/software/SDL_render_sw.c
author Sam Lantinga <slouken@libsdl.org>
Sun, 13 Jul 2014 09:04:55 -0700
changeset 9008 f061a86fbb08
parent 8907 e4c67eb79af8
child 9619 b94b6d0bff0f
permissions -rw-r--r--
Fixed bug 2640 - Unable to SDL_SetRenderTarget to original surface for software renderer without a window

Damian Kaczmarek

Basically this bug is probably not a common use case. My goal is to allow rendering totally without a window, for example to a screenshot and I need to rely on SDL_SetRenderTarget to properly work for a purely software renderer created by SDL_CreateSoftwareRenderer.
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2014 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     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     SW_RenderData *data = (SW_RenderData *) renderer->driverdata;
   350     SDL_Surface *surface = data->surface;
   351     if (surface) {
   352         if (renderer->clipping_enabled) {
   353             SDL_SetClipRect(surface, &renderer->clip_rect);
   354         } else {
   355             SDL_SetClipRect(surface, NULL);
   356         }
   357     }
   358     return 0;
   359 }
   360 
   361 static int
   362 SW_RenderClear(SDL_Renderer * renderer)
   363 {
   364     SDL_Surface *surface = SW_ActivateRenderer(renderer);
   365     Uint32 color;
   366     SDL_Rect clip_rect;
   367 
   368     if (!surface) {
   369         return -1;
   370     }
   371 
   372     color = SDL_MapRGBA(surface->format,
   373                         renderer->r, renderer->g, renderer->b, renderer->a);
   374 
   375     /* By definition the clear ignores the clip rect */
   376     clip_rect = surface->clip_rect;
   377     SDL_SetClipRect(surface, NULL);
   378     SDL_FillRect(surface, NULL, color);
   379     SDL_SetClipRect(surface, &clip_rect);
   380     return 0;
   381 }
   382 
   383 static int
   384 SW_RenderDrawPoints(SDL_Renderer * renderer, const SDL_FPoint * points,
   385                     int count)
   386 {
   387     SDL_Surface *surface = SW_ActivateRenderer(renderer);
   388     SDL_Point *final_points;
   389     int i, status;
   390 
   391     if (!surface) {
   392         return -1;
   393     }
   394 
   395     final_points = SDL_stack_alloc(SDL_Point, count);
   396     if (!final_points) {
   397         return SDL_OutOfMemory();
   398     }
   399     if (renderer->viewport.x || renderer->viewport.y) {
   400         int x = renderer->viewport.x;
   401         int y = renderer->viewport.y;
   402 
   403         for (i = 0; i < count; ++i) {
   404             final_points[i].x = (int)(x + points[i].x);
   405             final_points[i].y = (int)(y + points[i].y);
   406         }
   407     } else {
   408         for (i = 0; i < count; ++i) {
   409             final_points[i].x = (int)points[i].x;
   410             final_points[i].y = (int)points[i].y;
   411         }
   412     }
   413 
   414     /* Draw the points! */
   415     if (renderer->blendMode == SDL_BLENDMODE_NONE) {
   416         Uint32 color = SDL_MapRGBA(surface->format,
   417                                    renderer->r, renderer->g, renderer->b,
   418                                    renderer->a);
   419 
   420         status = SDL_DrawPoints(surface, final_points, count, color);
   421     } else {
   422         status = SDL_BlendPoints(surface, final_points, count,
   423                                 renderer->blendMode,
   424                                 renderer->r, renderer->g, renderer->b,
   425                                 renderer->a);
   426     }
   427     SDL_stack_free(final_points);
   428 
   429     return status;
   430 }
   431 
   432 static int
   433 SW_RenderDrawLines(SDL_Renderer * renderer, const SDL_FPoint * points,
   434                    int count)
   435 {
   436     SDL_Surface *surface = SW_ActivateRenderer(renderer);
   437     SDL_Point *final_points;
   438     int i, status;
   439 
   440     if (!surface) {
   441         return -1;
   442     }
   443 
   444     final_points = SDL_stack_alloc(SDL_Point, count);
   445     if (!final_points) {
   446         return SDL_OutOfMemory();
   447     }
   448     if (renderer->viewport.x || renderer->viewport.y) {
   449         int x = renderer->viewport.x;
   450         int y = renderer->viewport.y;
   451 
   452         for (i = 0; i < count; ++i) {
   453             final_points[i].x = (int)(x + points[i].x);
   454             final_points[i].y = (int)(y + points[i].y);
   455         }
   456     } else {
   457         for (i = 0; i < count; ++i) {
   458             final_points[i].x = (int)points[i].x;
   459             final_points[i].y = (int)points[i].y;
   460         }
   461     }
   462 
   463     /* Draw the lines! */
   464     if (renderer->blendMode == SDL_BLENDMODE_NONE) {
   465         Uint32 color = SDL_MapRGBA(surface->format,
   466                                    renderer->r, renderer->g, renderer->b,
   467                                    renderer->a);
   468 
   469         status = SDL_DrawLines(surface, final_points, count, color);
   470     } else {
   471         status = SDL_BlendLines(surface, final_points, count,
   472                                 renderer->blendMode,
   473                                 renderer->r, renderer->g, renderer->b,
   474                                 renderer->a);
   475     }
   476     SDL_stack_free(final_points);
   477 
   478     return status;
   479 }
   480 
   481 static int
   482 SW_RenderFillRects(SDL_Renderer * renderer, const SDL_FRect * rects, int count)
   483 {
   484     SDL_Surface *surface = SW_ActivateRenderer(renderer);
   485     SDL_Rect *final_rects;
   486     int i, status;
   487 
   488     if (!surface) {
   489         return -1;
   490     }
   491 
   492     final_rects = SDL_stack_alloc(SDL_Rect, count);
   493     if (!final_rects) {
   494         return SDL_OutOfMemory();
   495     }
   496     if (renderer->viewport.x || renderer->viewport.y) {
   497         int x = renderer->viewport.x;
   498         int y = renderer->viewport.y;
   499 
   500         for (i = 0; i < count; ++i) {
   501             final_rects[i].x = (int)(x + rects[i].x);
   502             final_rects[i].y = (int)(y + rects[i].y);
   503             final_rects[i].w = SDL_max((int)rects[i].w, 1);
   504             final_rects[i].h = SDL_max((int)rects[i].h, 1);
   505         }
   506     } else {
   507         for (i = 0; i < count; ++i) {
   508             final_rects[i].x = (int)rects[i].x;
   509             final_rects[i].y = (int)rects[i].y;
   510             final_rects[i].w = SDL_max((int)rects[i].w, 1);
   511             final_rects[i].h = SDL_max((int)rects[i].h, 1);
   512         }
   513     }
   514 
   515     if (renderer->blendMode == SDL_BLENDMODE_NONE) {
   516         Uint32 color = SDL_MapRGBA(surface->format,
   517                                    renderer->r, renderer->g, renderer->b,
   518                                    renderer->a);
   519         status = SDL_FillRects(surface, final_rects, count, color);
   520     } else {
   521         status = SDL_BlendFillRects(surface, final_rects, count,
   522                                     renderer->blendMode,
   523                                     renderer->r, renderer->g, renderer->b,
   524                                     renderer->a);
   525     }
   526     SDL_stack_free(final_rects);
   527 
   528     return status;
   529 }
   530 
   531 static int
   532 SW_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
   533               const SDL_Rect * srcrect, const SDL_FRect * dstrect)
   534 {
   535     SDL_Surface *surface = SW_ActivateRenderer(renderer);
   536     SDL_Surface *src = (SDL_Surface *) texture->driverdata;
   537     SDL_Rect final_rect;
   538 
   539     if (!surface) {
   540         return -1;
   541     }
   542 
   543     if (renderer->viewport.x || renderer->viewport.y) {
   544         final_rect.x = (int)(renderer->viewport.x + dstrect->x);
   545         final_rect.y = (int)(renderer->viewport.y + dstrect->y);
   546     } else {
   547         final_rect.x = (int)dstrect->x;
   548         final_rect.y = (int)dstrect->y;
   549     }
   550     final_rect.w = (int)dstrect->w;
   551     final_rect.h = (int)dstrect->h;
   552 
   553     if ( srcrect->w == final_rect.w && srcrect->h == final_rect.h ) {
   554         return SDL_BlitSurface(src, srcrect, surface, &final_rect);
   555     } else {
   556         return SDL_BlitScaled(src, srcrect, surface, &final_rect);
   557     }
   558 }
   559 
   560 static int
   561 GetScaleQuality(void)
   562 {
   563     const char *hint = SDL_GetHint(SDL_HINT_RENDER_SCALE_QUALITY);
   564 
   565     if (!hint || *hint == '0' || SDL_strcasecmp(hint, "nearest") == 0) {
   566         return 0;
   567     } else {
   568         return 1;
   569     }
   570 }
   571 
   572 static int
   573 SW_RenderCopyEx(SDL_Renderer * renderer, SDL_Texture * texture,
   574                 const SDL_Rect * srcrect, const SDL_FRect * dstrect,
   575                 const double angle, const SDL_FPoint * center, const SDL_RendererFlip flip)
   576 {
   577     SDL_Surface *surface = SW_ActivateRenderer(renderer);
   578     SDL_Surface *src = (SDL_Surface *) texture->driverdata;
   579     SDL_Rect final_rect, tmp_rect;
   580     SDL_Surface *surface_rotated, *surface_scaled;
   581     Uint32 colorkey;
   582     int retval, dstwidth, dstheight, abscenterx, abscentery;
   583     double cangle, sangle, px, py, p1x, p1y, p2x, p2y, p3x, p3y, p4x, p4y;
   584 
   585     if (!surface) {
   586         return -1;
   587     }
   588 
   589     if (renderer->viewport.x || renderer->viewport.y) {
   590         final_rect.x = (int)(renderer->viewport.x + dstrect->x);
   591         final_rect.y = (int)(renderer->viewport.y + dstrect->y);
   592     } else {
   593         final_rect.x = (int)dstrect->x;
   594         final_rect.y = (int)dstrect->y;
   595     }
   596     final_rect.w = (int)dstrect->w;
   597     final_rect.h = (int)dstrect->h;
   598 
   599     surface_scaled = SDL_CreateRGBSurface(SDL_SWSURFACE, final_rect.w, final_rect.h, src->format->BitsPerPixel,
   600                                           src->format->Rmask, src->format->Gmask,
   601                                           src->format->Bmask, src->format->Amask );
   602     if (surface_scaled) {
   603         SDL_GetColorKey(src, &colorkey);
   604         SDL_SetColorKey(surface_scaled, SDL_TRUE, colorkey);
   605         tmp_rect = final_rect;
   606         tmp_rect.x = 0;
   607         tmp_rect.y = 0;
   608 
   609         retval = SDL_BlitScaled(src, srcrect, surface_scaled, &tmp_rect);
   610         if (!retval) {
   611             SDLgfx_rotozoomSurfaceSizeTrig(tmp_rect.w, tmp_rect.h, -angle, &dstwidth, &dstheight, &cangle, &sangle);
   612             surface_rotated = SDLgfx_rotateSurface(surface_scaled, -angle, dstwidth/2, dstheight/2, GetScaleQuality(), flip & SDL_FLIP_HORIZONTAL, flip & SDL_FLIP_VERTICAL, dstwidth, dstheight, cangle, sangle);
   613             if(surface_rotated) {
   614                 /* Find out where the new origin is by rotating the four final_rect points around the center and then taking the extremes */
   615                 abscenterx = final_rect.x + (int)center->x;
   616                 abscentery = final_rect.y + (int)center->y;
   617                 /* Compensate the angle inversion to match the behaviour of the other backends */
   618                 sangle = -sangle;
   619 
   620                 /* Top Left */
   621                 px = final_rect.x - abscenterx;
   622                 py = final_rect.y - abscentery;
   623                 p1x = px * cangle - py * sangle + abscenterx;
   624                 p1y = px * sangle + py * cangle + abscentery;
   625 
   626                 /* Top Right */
   627                 px = final_rect.x + final_rect.w - abscenterx;
   628                 py = final_rect.y - abscentery;
   629                 p2x = px * cangle - py * sangle + abscenterx;
   630                 p2y = px * sangle + py * cangle + abscentery;
   631 
   632                 /* Bottom Left */
   633                 px = final_rect.x - abscenterx;
   634                 py = final_rect.y + final_rect.h - abscentery;
   635                 p3x = px * cangle - py * sangle + abscenterx;
   636                 p3y = px * sangle + py * cangle + abscentery;
   637 
   638                 /* Bottom Right */
   639                 px = final_rect.x + final_rect.w - abscenterx;
   640                 py = final_rect.y + final_rect.h - abscentery;
   641                 p4x = px * cangle - py * sangle + abscenterx;
   642                 p4y = px * sangle + py * cangle + abscentery;
   643 
   644                 tmp_rect.x = (int)MIN(MIN(p1x, p2x), MIN(p3x, p4x));
   645                 tmp_rect.y = (int)MIN(MIN(p1y, p2y), MIN(p3y, p4y));
   646                 tmp_rect.w = dstwidth;
   647                 tmp_rect.h = dstheight;
   648 
   649                 retval = SDL_BlitSurface(surface_rotated, NULL, surface, &tmp_rect);
   650                 SDL_FreeSurface(surface_scaled);
   651                 SDL_FreeSurface(surface_rotated);
   652                 return retval;
   653             }
   654         }
   655         return retval;
   656     }
   657 
   658     return -1;
   659 }
   660 
   661 static int
   662 SW_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
   663                     Uint32 format, void * pixels, int pitch)
   664 {
   665     SDL_Surface *surface = SW_ActivateRenderer(renderer);
   666     Uint32 src_format;
   667     void *src_pixels;
   668     SDL_Rect final_rect;
   669 
   670     if (!surface) {
   671         return -1;
   672     }
   673 
   674     if (renderer->viewport.x || renderer->viewport.y) {
   675         final_rect.x = renderer->viewport.x + rect->x;
   676         final_rect.y = renderer->viewport.y + rect->y;
   677         final_rect.w = rect->w;
   678         final_rect.h = rect->h;
   679         rect = &final_rect;
   680     }
   681 
   682     if (rect->x < 0 || rect->x+rect->w > surface->w ||
   683         rect->y < 0 || rect->y+rect->h > surface->h) {
   684         return SDL_SetError("Tried to read outside of surface bounds");
   685     }
   686 
   687     src_format = surface->format->format;
   688     src_pixels = (void*)((Uint8 *) surface->pixels +
   689                     rect->y * surface->pitch +
   690                     rect->x * surface->format->BytesPerPixel);
   691 
   692     return SDL_ConvertPixels(rect->w, rect->h,
   693                              src_format, src_pixels, surface->pitch,
   694                              format, pixels, pitch);
   695 }
   696 
   697 static void
   698 SW_RenderPresent(SDL_Renderer * renderer)
   699 {
   700     SDL_Window *window = renderer->window;
   701 
   702     if (window) {
   703         SDL_UpdateWindowSurface(window);
   704     }
   705 }
   706 
   707 static void
   708 SW_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture)
   709 {
   710     SDL_Surface *surface = (SDL_Surface *) texture->driverdata;
   711 
   712     SDL_FreeSurface(surface);
   713 }
   714 
   715 static void
   716 SW_DestroyRenderer(SDL_Renderer * renderer)
   717 {
   718     SW_RenderData *data = (SW_RenderData *) renderer->driverdata;
   719 
   720     SDL_free(data);
   721     SDL_free(renderer);
   722 }
   723 
   724 #endif /* !SDL_RENDER_DISABLED */
   725 
   726 /* vi: set ts=4 sw=4 expandtab: */