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