src/render/software/SDL_render_sw.c
author Sam Lantinga <slouken@libsdl.org>
Sun, 02 Feb 2014 00:53:27 -0800
changeset 8149 681eb46b8ac4
parent 8093 b43765095a6f
child 8728 c7174f961388
permissions -rw-r--r--
Fixed bug 2374 - Update copyright for 2014...

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